我想使用
Parallel.ForEach
来操作一组并返回另一组。但我似乎得到了一个空的。并且有一个异步方法需要在Parallel.ForEach
中执行。
这是 Windows 10 中带有 .NET Core 2.2 的控制台应用程序。
public static ConcurrentBag<int> GetList()
{
ConcurrentBag<int> result = new ConcurrentBag<int>() ;
List<int> list = new List<int> { 1, 2, 3 };
Parallel.ForEach(list, async i => {
await Task.Delay(i*1000);
result.Add(i * 2);
});
return result;
}
public static void Main(String[] args)
{
List<int> list = new List<int>();
var res = GetList();
list.AddRange(res);
Console.WriteLine("Begging.");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
我期望 {2,4,6},但实际上是一个空的。
await
。你需要明白的是,await
是一个奇特的回报。如果调用者不理解任务,它看到的只是返回。 Parallel.ForEach
不期望委托返回任务,因此它不知道如何等待 await
完成。
Parallel.ForEach
几乎一开始就完成,并且早在任何内容写入result
之前就完成了。
现在,
Parallel
应该用于CPU密集型操作,所以这不是问题。如果您想模拟长时间运行的 CPU 密集型操作,请使用 Thread.Sleep
而不是 await Task.Delay
。
顺便说一句,您将如何并行化受 I/O 限制的基于任务的操作?最简单的方法是这样的:
await Task.WhenAll(list.Select(YourAsyncOperation));
其中
YourAsyncOperation
是一个返回Task
的异步方法,可以随意使用Task.Delay
。这种简单方法的主要问题是您必须确保YourAsyncOperation
实际上很快就会执行await
,并且理想情况下不使用同步上下文。在最坏的情况下,所有调用都将被序列化。好吧,真的,在绝对最坏的情况下,你会陷入僵局,但是......:)