首页 > 解决方案 > 在 Parallel.ForEach 循环中进行异步数据库调用会提高性能吗?

问题描述

使用 Parallel.ForEach 时,将任何 DB 或 Api 调用转换为异步方法会提高性能吗?

一点背景知识,我目前有一个控制台应用程序,它顺序循环遍历一堆文件,并为每个文件调用一个 API 并进行一些 DB 调用。主要逻辑如下所示:

foreach (file in files)
{
    ReadTheFileAndComputeAFewThings(file);
    CallAWebService(file);
    MakeAFewDbCalls(file);
}

目前所有的 DB 和 Web 服务调用都是同步的。

Parallel.ForEach正如您所期望的那样,更改要使用的循环给了我巨大的性能提升。

我想知道我是否将Parallel.ForEach调用保留在那里,并在循环内,将所有 Web 服务调用更改为异步(例如,HttpClient.SendAsync)并将数据库调用更改为异步(使用 Dapper,db.ExecuteAsync()) - 这会通过允许它来提高应用程序的性能吗重用线程?或者它会像处理线程分配一样有效地什么都不Parallel.ForEach做?

标签: c#parallel-processingtaskhttpclientdapper

解决方案


答案是否定的。异步提供可扩展性,而不是性能。它允许使用更少的内存(每个阻塞线程 = 1 MB浪费的内存)来完成相同的工作。

不过,重要的是要记住,异步性并不是针对单个操作的性能优化。采用同步操作并使其成为异步操作总是会降低该操作的性能,因为它仍然需要完成同步操作所做的所有事情,但现在有额外的限制和考虑因素。

该类Parallel适用于 CPU 密集型作业。对于部分或完全 I/O 绑定的作业,最好使用异步 API,并且理想情况下独立处理 CPU 绑定和 I/O 绑定部分,因为它们的最佳并发级别通常不同。TPL Dataflow库是此类工作的一个近乎完美的工具。您可以创建相互链接的 Dataflow 块管道,并且每个块都可以配置不同的MaxDegreeOfParallelism. 对于受 CPU 限制的部分,您受到运行应用程序的机器的处理器/内核数量的限制。对于 I/O 绑定部分,您受到远程 Web 服务器、磁盘驱动器或数据库服务器的功能的限制。


推荐阅读