EF 6 - 如何正确执行并行查询

Leo*_*rdo 12 .net c# sql-server entity-framework

在创建报告时,我必须执行3个涉及相同上下文的分离实体的查询.因为它们非常沉重,所以我决定使用它.ToListAsync();来让它们并行运行,但令我惊讶的是,我得到了一个例外...

使用EF 6并行执行查询的正确方法是什么?我应该手动启动新任务吗?

编辑1
代码基本上是

using(var MyCtx = new MyCtx())
{
      var r1 = MyCtx.E1.Where(bla bla bla).ToListAsync();
      var r2 = MyCtx.E2.Where(ble ble ble).ToListAsync();
      var r3 = MyCtx.E3.Where(ble ble ble).ToListAsync();
      Task.WhenAll(r1,r2,r3);
      DoSomething(r1.Result, r2.Result, r3.Result);
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ons 14

问题是这样的:

EF不支持通过相同的DbContext对象处理多个请求.如果同一个DbContext实例上的第二个异步请求在第一个请求完成之前启动(这就是整点),那么您将收到一条错误消息,指出您的请求正在处理打开的DataReader.

资料来源:https://visualstudiomagazine.com/articles/2014/04/01/async-processing.aspx

您需要将代码修改为以下内容:

async Task<List<E1Entity>> GetE1Data()
{
    using(var MyCtx = new MyCtx())
    {
         return await MyCtx.E1.Where(bla bla bla).ToListAsync();
    }
}

async Task<List<E2Entity>> GetE2Data()
{
    using(var MyCtx = new MyCtx())
    {
         return await MyCtx.E2.Where(bla bla bla).ToListAsync();
    }
}

async Task DoSomething()
{
    var t1 = GetE1Data();
    var t2 = GetE2Data();
    await Task.WhenAll(t1,t2);
    DoSomething(t1.Result, t2.Result);
}
Run Code Online (Sandbox Code Playgroud)

  • 做这样的事情是否会带来值得的性能提升? (3认同)
  • @binki:您可以将读取与写入分开:读取实体,将它们与上下文分离。然后修改它们并将它们附加到单个上下文并保存更改。 (3认同)
  • @Josh取决于。如果多个调用(比方说10个调用)比并行执行花费1秒钟的时间,则可以导致连续运行时的总持续时间短于10秒。但是数据库引擎也有其局限性。如果用并行请求轰炸它,则其资源消耗将增加。 (2认同)
  • @mko,您可能依赖于延迟加载,因此 EF 尝试加载其他数据,但由于上下文已被释放而失败。 (2认同)

ret*_*der 8

有趣的是,当将 EF Core 与 Oracle 结合使用时,使用单个数据库上下文的多个并行操作(如此处的帖子)可以正常工作(尽管有 Microsoft 的文档)。该限制存在于 Microsoft.EntityFrameworkCore.SqlServer.dll 驱动程序中,并不是一般的 EF 问题。相应的 Oracle.EntityFrameworkCore.dll 驱动程序没有此限制。