使 Foreach 异步

Posted

技术标签:

【中文标题】使 Foreach 异步【英文标题】:Making Foreach Async 【发布时间】:2015-10-06 07:08:37 【问题描述】:

考虑一个场景,我们必须调用一个方法,该方法又调用列表中的数据库 foreach 对象。

List<object> Response= new List<object>
foreach(object obj in List<object>)

    Resposne.add(callMethod());

如何异步运行这个 foreach 循环,我想为列表中的下一个对象调用 callmethod,而无需等待第一个对象调用返回。一旦所有调用都成功返回,控制权应该返回给客户端。

由于 callMethod 函数调用数据库顺序执行需要时间。为了提高性能,我需要运行这个异步。

【问题讨论】:

类似Parallel.ForEach? 我希望代码只是一个坏例子,因为它没有做任何类似的事情。 【参考方案1】:

我想为列表中的下一个对象调用 callmethod,而无需等待第一个对象调用返回。

你真的很想parallelize your loop

List<object> Response= new List<object>();
// You need to put some stuff on Response
Parallel.ForEach(Response, o =>

   Response.Add(callMethod());
);

【讨论】:

虽然您的解决方案的想法是正确的,但我强烈建议在将项目添加到共享列表对象之前使用锁。或者使用不同版本的 Parallel.ForEach 循环,它使用线程/分区局部变量。作为一个小提示:它应该是Parallel.ForEach(someVariableName, ... 我在 CallMethod() 中调用外部数据库。我认为并行不会提高性能。 不要将Parallel.Foreach 用于 IO 操作。它会在现有线程等待 IO 完成时继续创建新线程。 @JakubLortz:取决于您的 .NET 运行时,但可能不会启动太多线程。创建多少线程非常聪明。如果需要,您还可以显式限制线程(使用不同的重载)。 @manthandavda:这完全取决于您的外部数据库。对于我运行的一项数据任务,使用 6 个并行线程调用数据库可为我提供理想的吞吐量。 > 1 个线程可能会提高性能。【参考方案2】:

你的callMethod()是一个IO操作,所以不要使用`Parallel.Foreach'。

Parallel.Foreach 专为并行计算而设计。当您想要执行并行 CPU 密集型操作时,它可以很好地扩展。但是,如果调用同步 IO 操作,线程将被阻塞等待操作完成。这是一种资源的浪费,因为线程被阻塞时无法重用。更糟糕的是,调度程序会不断为“Parallel.Foreach”创建新线程以保持 CPU 忙碌。在客户端应用程序中这可能不是一个非常大的问题,但在具有许多并发请求的服务器应用程序中,这将是一个瓶颈。

你应该让你的 callMethod() 异步

private async Task<int> callMethodAsync()

在方法中做一个异步操作,例如

using (SqlDataReader reader = await command.ExecuteReaderAsync())

然后像这样使用它:

int[] results = await Task.WhenAll(from obj in list select callMethodAsync());

【讨论】:

问题是我使用的是 postgres 而我的数据阅读器不是异步的。 @manthandavda 你用什么来连接数据库? Npgsql 有所有必要的异步方法。

以上是关于使 Foreach 异步的主要内容,如果未能解决你的问题,请参考以下文章

C# 异步 Foreach

如何将异步与 ForEach 一起使用?

带有 angular.forEach 的简单异步代码

Javascript中forEach的异步问题

提高性能异步 Parallel.Foreach

node.js中的forEach是同步还是异步