Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在ASP.NET中正确使用Task.Run和Task.WaitAll进行EF调用_C#_Asp.net_Async Await_Task - Fatal编程技术网

C# 在ASP.NET中正确使用Task.Run和Task.WaitAll进行EF调用

C# 在ASP.NET中正确使用Task.Run和Task.WaitAll进行EF调用,c#,asp.net,async-await,task,C#,Asp.net,Async Await,Task,简短版本: 任何人都可以确认,对于ASP.NET应用程序,带有EF调用的非异步子函数上的Task.Run/Task.WaitAll是否有任何好处 长版本: 我们有一个Asp.NETWebAPI服务,它有一个方法,可以使用EntityFramework进行多个DB调用,以收集一组数据,这些数据都返回到单个响应对象中。我们将其分解为一系列子函数,并希望这些子函数并行运行注意:它们都不使用任何异步调用 为了实现某种形式的并行编码,我们使用Task.Run调用每个函数,然后是Task.WaitAll:

简短版本:

任何人都可以确认,对于ASP.NET应用程序,带有EF调用的非异步子函数上的Task.Run/Task.WaitAll是否有任何好处

长版本:

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

为了实现某种形式的并行编码,我们使用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有异步版本,但有大量代码需要修改。我们希望这些函数保持原样。

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

但是,收益仅限于threadpool中的线程数,而线程数最终会受到服务器容量的限制。通过使用EF异步API,您将获得更多收益,因为这将允许执行许多查询,而无需为每个查询绑定线程


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

使用Task.Run至少允许您并行运行两个查询,因此与按顺序运行查询的完全同步版本相比,可以获得改进

但是,收益仅限于threadpool中的线程数,而线程数最终会受到服务器容量的限制。通过使用EF异步API,您将获得更多收益,因为这将允许执行许多查询,而无需为每个查询绑定线程


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

根据我的经验,我强烈建议您不要为了微不足道的性能提高而扼杀简单性。在我看来,这种并行性的影响是微不足道的,它带来了巨大的开发、维护和调试负担


特别是因为您使用EF并与DB交互,所以您可能会面临许多可能是mare的并发性问题!另外,我建议您看看。

根据我的经验,我强烈建议您不要为了微不足道的性能提升而扼杀简单性。在我看来,这种并行性的影响是微不足道的,它带来了巨大的开发、维护和调试负担


特别是因为您使用EF并与DB交互,所以您可能会面临许多可能是mare的并发性问题!另外,我建议看一下。

在使用上述方法对Sync、Async和Parallel.Invoke进行了一些性能测试之后,我发现了一些有趣的结果。并行版本类似于:

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

    Parallel.Invoke(
        () => response.SetA = getDataSetA(id),
        () => response.SetB = getDataSetB(id),
        );

    return response;
}
异步出现在上面,在我最初的帖子中

结果表明,与基本同步调用相比,Async调用Task.Run/Task.WaitAll平均在57%的时间内运行,Parallel.Invoke平均在65%的时间内运行

因此,在ASP.NET应用程序中使用Task.Run/WaitAll有一个优势


更新:顺便说一句,这个测试是通过将我们的代码推送到我们的测试环境来完成的,我们的QA人员在那里执行测试。它当然没有模仿我们的prod环境,但确实显示它稍微好一些。

在对Sync、Async(使用上述方法)和Parallel.Invoke进行了一些性能测试之后,我发现了一些有趣的结果。并行版本类似于:

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

    Parallel.Invoke(
        () => response.SetA = getDataSetA(id),
        () => response.SetB = getDataSetB(id),
        );

    return response;
}
异步出现在上面,在我最初的帖子中

结果表明,与基本同步调用相比,Async调用Task.Run/Task.WaitAll平均在57%的时间内运行,Parallel.Invoke平均在65%的时间内运行

因此,在ASP.NET应用程序中使用Task.Run/WaitAll有一个优势


更新:顺便说一句,这个测试是通过将我们的代码推送到我们的测试环境来完成的,我们的QA人员在那里执行测试。它当然没有模仿我们的prod环境,但确实表明它稍微好一些。

您可能只需要使用一个Parallel.ForEach重载来节省一些麻烦。这取决于使用模式。如果你的端点很少被调用,你可能会提高性能,特别是在一些长时间运行的东西的情况下,但通常不值得这么麻烦。这将使用比需要多得多的线程。创建async await是为了保存线程使用情况。EF有异步API。@Marie-好建议。我刚刚实现了一个Parallel.Invoke版本和
我正在测试。当系统处于负载状态时,不可能判断并行运行这些程序是否会产生任何好处。如果您正在处理来自多个用户的请求,那么线程可能很容易成为稀缺资源,您可能最终会等待一个线程可用。由于并发锁,您可能还会遇到线程之间的阻塞。判断是否存在总体效益的唯一方法是模拟预期负载,并查看系统如何响应。另外,请参见。您可能只需要使用Parallel.ForEach重载之一来保存一些hassleIt,这取决于使用模式。如果你的端点很少被调用,你可能会提高性能,特别是在一些长时间运行的东西的情况下,但通常不值得这么麻烦。这将使用比需要多得多的线程。创建async await是为了保存线程使用情况。EF有异步API。@Marie-好建议。我刚刚实现了一个Parallel.Invoke版本,正在测试它。当系统处于负载状态时,无法判断并行运行这些版本是否会产生任何好处。如果您正在处理来自多个用户的请求,那么线程可能很容易成为稀缺资源,您可能最终会等待一个线程可用。由于并发锁,您可能还会遇到线程之间的阻塞。判断是否存在总体效益的唯一方法是模拟预期负载,并查看系统如何响应。另外,请参见。