Entity framework 实体框架与并行性

Entity framework 实体框架与并行性,entity-framework,parallel-processing,profiling,task-parallel-library,tpl-dataflow,Entity Framework,Parallel Processing,Profiling,Task Parallel Library,Tpl Dataflow,背景 我有一个应用程序,它接收定期数据转储(XML文件),并使用EntityFramework5(代码优先)将它们导入现有数据库。导入通过EF5进行,而不是批量插入或BCP,因为必须应用实体中已经存在的业务规则 在应用程序本身中,处理似乎受到CPU的限制(速度极快、支持写缓存的磁盘IO子系统在整个处理过程中显示几乎为零的磁盘等待时间,SQL Server显示的CPU时间不超过8%-10%) 为了提高效率,我使用组件构建了一个: Read & Parse XML file

背景

我有一个应用程序,它接收定期数据转储(XML文件),并使用EntityFramework5(代码优先)将它们导入现有数据库。导入通过EF5进行,而不是批量插入或BCP,因为必须应用实体中已经存在的业务规则

在应用程序本身中,处理似乎受到CPU的限制(速度极快、支持写缓存的磁盘IO子系统在整个处理过程中显示几乎为零的磁盘等待时间,SQL Server显示的CPU时间不超过8%-10%)

为了提高效率,我使用组件构建了一个:

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探查器的资源争用数据(并发)模式运行了该进程

探查器向我显示标记为句柄2的资源的52%争用。深入研究,我发现为句柄2创建最多争用的方法是

第二位,大约是SaveChanges()的40%,是

问题

  • 我怎样才能知道句柄2到底是什么(例如,TPL的一部分,EF的一部分)
  • EF是否限制从单独线程中分离DbContext实例的调用?他们似乎在争夺一种共享资源
  • 在这种情况下,我能做些什么来提高并行性吗
更新

对于所讨论的运行,调用SaveChanges的任务的最大并行度设置为12(我在以前的运行中尝试了各种值,包括Unbounded)

更新2


微软的EF团队提供了反馈。请参阅我的答案以获取摘要。

以下总结了我与Entity Framework团队在这个问题上的互动。如果有更多信息,我会更新答案

  • 这个问题可以在微软转载
  • 句柄争用与网络I/O有关(即使在本地主机上使用SQL Server)。具体而言,System.Data.dll中存在对网络I/O读取缓冲区的争用
  • EF团队现在正在与SQL连接团队合作,以更好地理解这个问题
  • 到目前为止,微软还没有关于如何最大限度地减少这一争论的影响的指导
更新

目前正在CodePlex上跟踪此问题:


您确定没有等待池的连接吗?您是否尝试过将连接池的大小增大?@Maess:对于所讨论的运行,我将最大并行度设置为12。如果我理解正确,连接池的默认最大大小是100。尽管如此,我还是会尝试显式地将其设置得更高。@Maess:Perfmon仅显示11个到SQL实例的逻辑连接和11个用户连接,远远低于连接池限制。如果我们能够为此获得一个复制,那将是非常棒的。关于哪个锁可能导致问题,我有一些初步的想法,但如果不进行修改,很难确定。EF当然没有进行任何有意的限制,但它确实在某些地方使用锁来访问共享元数据,其中之一可能会导致问题。我的电子邮件是avickers在你知道的地方。@ArthurVickers:我会看看我是否能做一个简单的复制。另外,EF 5来源是否可用?我看到它们是为EF 6发布的。有了EF5源代码,我可以在我的完整解决方案中找到导致问题的代码行。非常感谢Eric。我对这个很感兴趣,因为我有一个类似的场景。我们在connect.microsoft.com上对此有问题吗?这样我们就可以跟踪它的进度了?@Dodd:因为EF现在是开源的(但仍然由微软的团队负责)。添加了链接。
System.Data.Entity.Internal.InternalContext.SaveChanges()
System.Data.Entity.DbSet`1.Add(!0)