Entity Framework支持并行异步查询吗?

63

当我们开始多个异步 Entity Framework 查询并在并行运行时,会发生什么?

它们是否在物理上同时执行?它们是否被 Entity Framework 序列化?这是不受支持的吗?它是否会导致异常?

public async Task QueryDatabase()
{
    using (var context = new MyDbContext())
    {
        Task task1 = context.SomeTable1.ToListAsync();
        Task task2 = context.SomeTable2.ToListAsync();

        await Task.WhenAll(task1, task2);
    }
}

请参见 https://dev59.com/o1gR5IYBdhLWcg3wGaAK。 - Michael Freidgeim
3个回答

74

根据版本6的规范,不支持此功能。

这将引发DbConcurrencyException异常,显示:

在上一个异步操作完成之前,在此上下文中启动了第二个操作。使用“await”确保在调用此上下文上的另一个方法之前已完成任何异步操作。不能保证任何实例成员是线程安全的。

EF将检测开发人员是否尝试同时执行两个异步操作并引发异常

来自项目代码页

启用数据库操作的异步执行实际上与在同一上下文上启用并发执行无关。对于服务器场景的特定情况,在使用并发访问时可能会对可扩展性产生负面影响,因为这意味着为处理单个请求,您将启动任意数量的不同线程。所有线程都将竞争诸如内存之类的资源,这些资源还必须用于处理其他并发请求的线程。

Entity Framework Core 也不支持这种情况

EF Core不支持在同一上下文实例上运行多个并行操作。您应始终等待操作完成,然后开始下一个操作。通常通过在每个异步操作上使用await关键字来完成此操作。


7
赞同准确性,但我希望我能对写Codeplex片段的人进行反对投票。一个好的查询基本上是对数据库的命中,而在大多数情况下,数据库是多CPU的,在许多情况下是网络化的。向数据库抛出一堆并行异步调用不使用线程!http://blog.stephencleary.com/2013/11/there-is-no-thread.html 如果所有查询都是.AsNoTracking(),那么EF应该很容易支持这一点,但它仍然会抛出这个异常。 - Chris Moschini
@ChrisMoschini 我非常确定最后一句话不是指EF,而是指SQL Server。 - Erik Philips
@ErikPhilips 不太清楚你的意思,能否澄清一下? - Chris Moschini
5
@MIKE 嗯,它确实是异步的;只是你不能同时运行多个异步SQL操作。在服务器端进行异步编程具有多个优点:第一个不是更好的性能,而是可伸缩性,这意味着您不会阻塞线程直到操作完成。即使您无法并行运行两个SQL请求,这仍然是一个巨大的优势。例如,请参见https://dev59.com/72nWa4cB1Zd3GeqPwg-Z#12673868 - ken2k
1
@ChrisPratt 在EF6中,即使是查询也不能并行运行。你只是_不能_同时启动多个异步操作(获取、计数、更新、删除、插入...)。 - ken2k
显示剩余2条评论

5

请注意,正如ken2k所提到的,在使用MS SQL Server时,Entity Framework不允许此操作。但是,如果您在使用Oracle时使用Entity Framework,则可以允许此操作。


6
你能提供这个消息的来源吗?我的印象是EF内部不能同时运行多个查询,因为这需要它的内部结构,如标识映射表,具有线程安全性。 - usr
2
我不能提供源代码,但我可以说我有使用该方法的生产代码运行。 - jkruer01
7
希望你的呼机晚上不要响。感谢你的汇报。 - usr
一个上下文从来都不是线程安全的,永远都不是。数据库提供程序没有任何影响。这是完全错误的信息。 - Gert Arnold

-1

2
这与并行处理无关,因此在此提及不相关。 - Gert Arnold

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