首页 > 解决方案 > 在 ASP.NET 中正确使用 Task.Run 和 Task.WaitAll 进行 EF 调用

问题描述

精简版:

任何人都可以确认,带有 EF 调用的非异步子功能上的 Task.Run/Task.WaitAll 对 ASP.NET 应用程序有什么好处吗?

长版:

我们有一个 Asp.Net WebApi 服务,它的方法可以进行多个 DB 调用(全部使用 EntityFramework)来收集一组数据,这些数据全部返回到单个响应对象中。我们将其分解为一系列子功能,并希望它们并行运行(注意:这些都没有使用任何异步调用)。

为了实现某种形式的并行编码,我们使用 Task.Run 调用每个函数,然后是 Task.WaitAll:

public ResponseObject PopulateResponseObject(int id)
{
    var response = new ResponseObject();

    Task<DataSetA> dataSetATask = Task.Run(() => getDataSetA(id));
    Task<DataSetB> dataSetBTask = Task.Run(() => getDataSetB(id));
    Task.WaitAll(dataSetATask, dataSetBTask);

    response.SetA = dataSetATask.Result;
    response.SetB = dataSetBTask.Result;

    return response;
}

从我一直在阅读的内容来看,Task.Run 可能不会在 Asp.Net 应用程序中获得太多收益,而我们在这里所拥有的可能只会导致不必要的线程池开销。

我们是否在浪费时间以这种方式编写代码?

更新:我们熟悉 EF 具有异步版本的事实,但需要修改大量代码。我们希望保持这些功能不变。

标签: c#asp.netasync-awaittask

解决方案


使用 Task.Run 至少可以让您并行运行两个查询,所以是的,可以获得改进(与您按顺序运行查询的完全同步版本相比)。

但是,收益仅限于您在线程池中拥有的线程数(最终受限于您的服务器容量)。通过使用 EF 异步 api,您将获得更多收益,因为这将允许执行许多查询,而无需为每个查询占用一个线程。

但这是开始使用异步代码的合理策略。完成此操作后,您可以返回并慢慢将查询转换为使用异步 api。


推荐阅读