【发布时间】:2012-11-01 17:41:12
【问题描述】:
背景
我有一个应用程序,它接收定期数据转储(XML 文件)并使用 Entity Framework 5(代码优先)将它们导入现有数据库。导入通过 EF5 而不是 BULK INSERT 或 BCP 进行,因为必须应用实体中已经存在的业务规则。
应用程序本身的处理似乎受 CPU 限制(极快、启用写入缓存的磁盘 IO 子系统在整个过程中显示几乎为零的磁盘等待时间,而 SQL Server 显示不超过 8%-10% 的 CPU 时间) .
为了提高效率,我用组件构建了一个pipeline using TPL Dataflow:
Read & Parse XML file
|
V
Create entities from XML Node
|
V
Batch entities (BatchBlock, currently n=200)
|
V
Create new DbContext / insert batched entities / ctx.SaveChanges()
我看到这样做可以显着提高性能,但不能使 CPU 超过 60%。
分析
怀疑某种资源争用,我使用 VS2012 Profiler 的 资源争用数据(并发)模式运行了该过程。
分析器向我显示标记为 Handle 2 的资源的争用率为 52%。深入研究,我看到为 Handle 2 创建最多争用的方法是
System.Data.Entity.Internal.InternalContext.SaveChanges()
第二名,争用次数大约是 SaveChanges() 的 40%,是
System.Data.Entity.DbSet`1.Add(!0)
问题
- 我怎样才能知道 Handle 2 到底是什么(例如,TPL 的一部分,EF 的一部分)?
- EF 是否会限制从单独线程中分离 DbContext 实例的调用?他们似乎在争夺一个共享资源。
- 在这种情况下,我可以做些什么来提高并行性?
更新
对于有问题的运行,调用 SaveChanges 的任务的最大并行度设置为 12(我在之前的运行中尝试了各种值,包括 Unbounded)。
更新 2
Microsoft 的 EF 团队提供了反馈。请参阅我的答案以获取摘要。
【问题讨论】:
-
您确定您不等待池的连接吗?您是否尝试过增大连接池大小?
-
@Maess:对于有问题的运行,我将最大并行度设置为 12。如果我理解正确,连接池的默认最大大小为 100。不过,我会明确尝试设置得更高。
-
@Maess:Perfmon 仅显示到 SQL 实例的 11 个逻辑连接和 11 个用户连接,远远低于连接池限制。
-
如果我们能得到一个复制品,那就太好了。关于哪个锁可能导致问题,我有一些初步的想法,但如果没有重现,很难确定。 EF 当然没有进行任何有意的限制,但它确实在某些地方使用锁来访问共享元数据,其中之一可能会导致问题。我的电子邮件是您知道在哪里的 avickers。
-
@ArthurVickers:我会看看能不能拼凑出一个简单的复制品。另外,是否有 EF 5 来源?我看到它们是为 EF 6 发布的。使用 EF 5 源,我可以在我的完整解决方案中找到导致问题的代码行。
标签: entity-framework parallel-processing profiling task-parallel-library tpl-dataflow