并行线程中的多个 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
,它会重用 Task
s。如果你设置MaxDegreeOfParallelism
,它会限制Task
s的使用数量,从而限制实际的并行度。
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 查询