为什么先执行return语句而不是Parallel.ForEach? [重复]

问题描述 投票:0回答:1

我想使用

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},但实际上是一个空的。

c# asynchronous async-await task-parallel-library parallel.foreach
1个回答
2
投票
罪魁祸首就是

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
,并且理想情况下不使用同步上下文。在最坏的情况下,所有调用都将被序列化。好吧,真的,在绝对最坏的情况下,你会陷入僵局,但是......:)

© www.soinside.com 2019 - 2024. All rights reserved.