使 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 异步的主要内容,如果未能解决你的问题,请参考以下文章