.net 和 Parallel.ForEach。异常绕过“try”块

Jon*_*nik 4 .net c# asynchronous exception parallel.foreach

有人可以解释一下这段代码的行为:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello world");
        try
        {
            Parallel.ForEach(new[] { 1, 2, 3 }, async i =>
            {
                await Task.Delay(TimeSpan.FromSeconds(3));
                throw new TaskCanceledException();
            });
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        Console.WriteLine("Goodbye cruel world");
        Console.ReadLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

怎么可能,异常在主线程中从“try”块中弹出,应用程序崩溃了。我知道并行异步的最佳方法是“Task.WhenAll”。问题的目的是了解行为。

Pan*_*vos 5

Parallel.ForEach不能用于调用异步方法。它仅适用于内存中数据并行性,不适用于异步操作。它的工作原理是对数据进行分区,并将每批数据提供给一个工作任务,每个 CPU 核心大约使用一个工作人员。它甚至使用调用线程来处理这些分区之一,这就是它看起来“阻塞”的原因。

它的重载都不接受 a Task,这意味着本例中 lambda 的返回类型是async void

该问题的代码相当于:

async void Do(int i)
{
    await Task.Delay(TimeSpan.FromSeconds(3));
    throw new TaskCanceledException();
}

Parallel.ForEach(data,Do);
Run Code Online (Sandbox Code Playgroud)

async void方法不能被等待,这意味着它们的异常也不能被调用者捕获。此代码async void使用 触发 3 个调用并立即返回。

在 .NET 6 中,您应该使用Parallel.ForEachAsync

var data=new[] { 1, 2, 3 };
await Parallel.ForEachAsync(data, async (i,token) =>
{
    await Task.Delay(TimeSpan.FromSeconds(3));
    throw new TaskCanceledException();
});
Run Code Online (Sandbox Code Playgroud)