C# 异步/等待多个CountAsync数据库调用EFCore

C# 异步/等待多个CountAsync数据库调用EFCore,c#,asp.net-core,async-await,entity-framework-core,entity-framework-core-2.2,C#,Asp.net Core,Async Await,Entity Framework Core,Entity Framework Core 2.2,我正在努力确保我理解async/Wait。在下面的示例中,我的代码是异步运行还是同步运行 我的理解可能是错误的,即每个异步数据库调用不必等待前一个调用完成。因此,我基本上可以运行许多CountAsync调用,它们都会同时运行,直到有人试图从其中一个异步调用获取数据为止 以下是我目前拥有的:(所有的select/where逻辑都被删除了,因为这个问题不需要它) 公共异步任务GetDashboard(仪表板输入) { DashboardModel=新的DashboardModel(); model.

我正在努力确保我理解async/Wait。在下面的示例中,我的代码是异步运行还是同步运行

我的理解可能是错误的,即每个异步数据库调用不必等待前一个调用完成。因此,我基本上可以运行许多
CountAsync
调用,它们都会同时运行,直到有人试图从其中一个异步调用获取数据为止

以下是我目前拥有的:(所有的select/where逻辑都被删除了,因为这个问题不需要它)

公共异步任务GetDashboard(仪表板输入) { DashboardModel=新的DashboardModel(); model.MyCustomers=wait_context.Customers.Where(x=>[…])。选择(x=>newdashboardcustomermodel() { [...] }).ToListAsync(); model.TotalCustomers=wait_context.Customers.CountAsync(x=>[…]); model.MyTotalCustomers=wait_context.Customers.CountAsync(x=>[…]); model.MyClosedCustomers=await_context.Customers.CountAsync(x=>[…]); model.MyNotStartedCustomers=await _context.Customers.CountAsync(x=>[…]); model.OtherTotalCustomers=await _context.Customers.CountAsync(x=>[…]); model.OtherClosedCustomers=await_context.Customers.CountAsync(x=>[…]); model.OtherNotStartedCustomers=await _context.Customers.CountAsync(x=>[…]); model.PreparerApprovedCustomers=wait_context.Customers.CountAsync(x=>[…]); model.ReviewerApprovedCustomers=wait _context.Customers.CountAsync(x=>[…]); model.ApprovedCustomers=wait _context.Customers.CountAsync(x=>[…]); 收益模型; }
我的同事表示,这是不正确的,所有呼叫都将同步运行;因此,我提出这个问题的原因。如果我错了,那么编写此方法以使所有异步调用同时运行的正确方法是什么?

任务返回热状态,或者已经启动。
wait
关键字的字面意思是在任务完成之前停止。因此,是的,使用您所拥有的代码,每个查询都将按顺序连续运行,一次一个,然后在每行上停止

要并行运行,只需启动任务即可。例如:

var totalCustomersTask = _context.Customers.CountAsync(x => [...]);

var myTotalCustomersTask = _context.Customers.CountAsync(x => [...]);
var myClosedCustomers = _context.Customers.CountAsync(x => [...]);
var myNotStartedCustomers = _context.Customers.CountAsync(x => [...]);

...
请注意,这些行中没有
wait
。然后,在完成所有任务后:

model.TotalCustomers = await totalCustomersTask;

model.MyTotalCustomers = await myTotalCustomersTask;
model.MyClosedCustomers = await myClosedCustomersTask;
model.MyNotStartedCustomers = await myNotStartedCustomers;

...

异步与“并行”不同,尽管异步操作可以并行运行。

您似乎混淆了“并行”和“并行”。您的查询将依次异步运行。这就是
wait
所做的。如果希望异步任务并行运行,请参阅。但是你可以。如果你想让调用并行运行,然后将生成的任务收集到一个集合中,然后使用
Task.whalll
等待它们。@GSerg:实际上你可以用EF来做,但在所有情况下这样做都不安全。例如,不支持尝试多个异步更新,因此查询只会在命中时命中数据库,在某些情况下可能导致奇怪或不正确的行为。然而,像运行计数这样的操作是完全可以异步完成的,因为它对数据没有影响。你必须
等待
上一个任务,才能调用另一个任务,即使没有
等待
。那时我很困惑。该答案中引用的文档似乎声称EF将检测开发人员是否试图同时执行两个异步操作并抛出。那不是真的吗?如果不是,它如何处理事务完整性?它是否升级为分布式事务?或者查询是否仍按顺序通过相同的连接/事务,但没有订单保证?“这有参考资料吗?”本看到了我之前的评论。虽然不会引发异常,但查询不会并行运行。获取并行查询的唯一方法是使用单独的db上下文实例。句号。@Ben在C级,不一定。在SQL级别,使用
count(case when closed=1然后1 else null end)作为closed_客户创建一个一次计算所有计数的视图可能会更快。
等@Chris不确定您所说的生产环境是什么意思。我正在使用简单的控制台应用程序。但这并不重要,因为您没有显式生成线程(
Task.Run
),所以异步任务“正在运行”,而不是SQL查询。是EF核心DbContext异步监视器将它们序列化。同样,如果打开EF Core命令执行日志并查看命令执行/执行日志,您可以看到。在完全相同的环境中,如果我将查询更改为使用单独的db上下文实例,日志将显示并行命令执行。简而言之,它是EF核心db上下文实例级序列化。
model.TotalCustomers = await totalCustomersTask;

model.MyTotalCustomers = await myTotalCustomersTask;
model.MyClosedCustomers = await myClosedCustomersTask;
model.MyNotStartedCustomers = await myNotStartedCustomers;

...