并行线程中的多个 dbcontexts,EntityException “当活动用户较少时重新运行您的语句”

Posted

技术标签:

【中文标题】并行线程中的多个 dbcontexts,EntityException “当活动用户较少时重新运行您的语句”【英文标题】:Multiple dbcontexts in parallel threads, EntityException "Rerun your statement when there are fewer active users" 【发布时间】:2013-01-30 03:35:22 【问题描述】:

我正在使用Parallel.ForEach 在多个线程上工作,每次迭代都使用一个新的 EF5 DbContext,全部包装在一个 TransactionScope 中,如下所示:

using (var transaction = new TransactionScope())

    int[] supplierIds;

    using (var appContext = new AppContext())
    
        supplierIds = appContext.Suppliers.Select(s => s.Id).ToArray();
    

    Parallel.ForEach(
        supplierIds,
        supplierId =>
    
        using (var appContext = new AppContext())
        
            Do some work...

            appContext.SaveChanges();                
        
    );

    transaction.Complete();

运行几分钟后,它会抛出一个 EntityException“底层提供程序在打开时失败”,其内部细节如下:

"SQL Server 数据库引擎的实例此时无法获取 LOCK 资源。当活动用户较少时重新运行您的语句。请数据库管理员检查此实例的锁和内存配置,或检查长时间运行的事务。”

有谁知道是什么原因造成的或如何预防?谢谢。

【问题讨论】:

您可能正在生成一百万个线程,TPL 针对较短的 CPU 绑定任务和非 CPU 绑定任务进行了优化(“为什么有这么多空闲 CPU ???”)产生更多线程。使用 MSDN 中的有限并发调度程序。 msdn.microsoft.com/en-us/library/ee789351.aspx 我认为你是对的,因为它正在产生大量线程。按照 bmdixon 的建议限制并行度解决了这个问题。 接受的答案已更改 :-) 【参考方案1】:

您还可以尝试使用 new ParallelOptions MaxDegreeOfParallelism = 8 Parallel.ForEach() 方法中设置最大并发任务数(将 8 替换为您想要限制的任何值。

详情请见MSDN

【讨论】:

这不会影响默认 TPL 任务调度程序中的任何内容。 @ta.speot.is 不确定您的意思。 Parallel.ForEach() 不会为集合中的每个项目创建一个 Task,它会重用 Tasks。如果你设置MaxDegreeOfParallelism,它会限制Tasks的使用数量,从而限制实际的并行度。 Entity Framework 中的并行操作中的意外争用似乎存在问题。这个问题我也遇到过,这里也讨论过:***.com/q/13182603/141172【参考方案2】:

您还应该了解为什么您的应用会占用如此大量的锁?您已经围绕多个数据库连接包装了一个 TransactionScope。这可能会导致可能与之有关的分布式事务。它肯定会导致锁直到最后才被释放。改变它。

到目前为止,您只能调高锁定限制。它不能扩展到任意数量的供应商 ID。您需要找到锁定的原因,而不是减轻症状。

【讨论】:

确实,我不明白为什么这需要大量的锁。 我怀疑你有 100 个连接同时进行(你明白为什么吗?)每个都有“正常”数量的锁。解决方法是将事务范围移动到主体的并行中。尝试将其删除以进行测试。【参考方案3】:

您正在运行 sql server 允许的最大锁数 - 默认情况下自动设置并由可用内存控制。

你可以

    手动设置 - 我忘了具体是怎么设置的,但 google 是你的朋友。 为您的 sql server 添加更多内存 更频繁地提交交易。

【讨论】:

原谅我的无知,但我不明白为什么程序需要很多锁?感谢您的帮助。 正如 usr 提到的,在事务范围内为每个插入创建上下文将导致大量连接,因此可能是这样。如果在运行之前重新启动 sql 实例,它会崩溃吗? 再想一想,几乎可以肯定。通过单个连接和大量插入,它会升级锁。如果有多个连接,它就无法做到这一点。 更新:不幸的是,即使没有 TransactionScope,也会发生错误。这在某种程度上破坏了我对这个问题的理解。 对不起,但我不是 100% 清楚那是什么。也许与它在循环时没有足够快地处理上下文有关?你对标准的循环有同样的看法吗?

以上是关于并行线程中的多个 dbcontexts,EntityException “当活动用户较少时重新运行您的语句”的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 中使用 DbContext 注入并行 EF Core 查询

android中的asynctask可不可以并行执行多个

EF DbContext 并发执行时可能出现的问题

Jmeter--多个线程组顺序执行和并行执行

多个线程(并行测试用例)如何使用Java(Selenium)设置中的Apache POI同时访问同一个excel文件?

使用实体框架6的mvc4中的单个或多个DbContext文件