实体框架和并行性

14

背景

我有一个应用程序,定期接收数据转储(XML文件),并使用Entity Framework 5(Code First)将它们导入到现有数据库中。导入是通过EF5而不是例如BULK INSERT或BCP进行的,因为必须应用已经存在于实体中的业务规则。

在应用程序本身中处理似乎是CPU绑定的(极快的写缓存启用的磁盘IO子系统在整个过程中几乎没有显示任何磁盘等待时间,并且SQL Server显示的CPU时间不超过8%-10%)。

为了提高效率,我构建了一个使用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的资源争用数据(并发)模式运行了该进程。

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的一部分)?
  • Entity Framework会限制来自不同线程的单独DbContext实例的调用吗?似乎它们正在争夺共享资源。
  • 在这种情况下,有什么可以做以提高并行性能?

更新

对于此次运行,调用SaveChanges的任务的最大并行度设置为12(我尝试了包括Unbounded在内的各种值)。

更新2

Microsoft的EF团队已经提供了反馈。请查看我的回答以获取摘要。


1
你确定你不是在等待连接池中的连接吗?你尝试过增加连接池大小吗? - Maess
@Maess:Perfmon仅显示SQL实例的11个逻辑连接和11个用户连接,远低于连接池限制。 - Eric J.
如果我们能够获得一个可重现的案例,那就太好了。我有一些初步的想法,可能是哪个锁导致了问题,但如果没有可重现的案例,很难确定。EF肯定没有进行任何有意的限制,但在某些地方使用锁来访问共享元数据,其中之一可能会导致问题。我的电子邮件是avickers at you know where。 - Arthur Vickers
此问题现在正在由微软跟踪:http://entityframework.codeplex.com/workitem/636 - Eric J.
@Maess:事实证明,这个问题与System.Data.dll中的网络读取缓冲区争用有关。我提供了一个更详细的答案。 - Eric J.
显示剩余4条评论
1个回答

5
以下是我与实体框架团队在此问题上的互动总结。如果有更多信息可用,我会更新答案。
  • 该问题可以在Microsoft上重现。
  • 句柄争用与网络I/O有关(即使SQL Server在本地主机上)。具体而言,System.Data.dll中的网络I/O读取缓冲区存在争用。
  • EF团队正在与SQL连接团队合作,以更好地了解这个问题。
  • 目前还没有来自Microsoft关于如何最小化此争用影响的指导。
更新 此问题现在正在CodePlex上跟踪: http://entityframework.codeplex.com/workitem/636?PendingVoteId=636

非常感谢Eric。我对此很感兴趣,因为我有类似的情况。我们在connect.microsoft.com上是否有这个问题,以便我们可以跟踪其进展? - Dodd
@Dodd:由于EF现在是开源的(但仍由微软团队维护),因此它正在Codeplex上被跟踪。我已经添加了链接。 - Eric J.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接