Parallel.For
和
Parallel.ForEach
重载没有任何用于处理可能引发的异常的特殊机制。 在这一方面,它们类似于常规
for
和
foreach
循环(在 Visual Basic 中为
For
和
For Each
);未处理的异常会导致循环在当前运行的迭代完成后立即终止。
向并行循环添加自己的异常处理逻辑时,将处理类似于在多个线程上同时引发相似异常的情况,以及一个线程上引发异常导致另一个线程上引发另一个异常的情况。 你可以通过将循环中的所有异常包装到一个
System.AggregateException
中处理这两种情况。 下面的示例演示了一种可能的方法。
某些情况下,当启用“仅我的代码”后,Visual Studio 会在引发异常的行中断运行并显示一条错误消息,该消息显示“用户代码未处理异常”。该错误是良性错误。 可以按 F5 继续运行,并请参阅下面示例中所示的异常处理行为。 为了阻止 Visual Studio 在第一个错误出现时中断,只需依次转到“工具”、“选项”、“调试”、“常规”下,取消选中“仅我的代码”复选框即可。
在此示例中,所有异常都被捕获,并包装到引发的
System.AggregateException
中。 调用方可以决定要处理哪些异常。
public static partial class Program
public static void ExceptionTwo()
// Create some random data to process in parallel.
// There is a good probability this data will cause some exceptions to be thrown.
byte[] data = new byte[5_000];
Random r = Random.Shared;
r.NextBytes(data);
ProcessDataInParallel(data);
catch (AggregateException ae)
var ignoredExceptions = new List<Exception>();
// This is where you can choose which exceptions to handle.
foreach (var ex in ae.Flatten().InnerExceptions)
if (ex is ArgumentException) Console.WriteLine(ex.Message);
else ignoredExceptions.Add(ex);
if (ignoredExceptions.Count > 0)
throw new AggregateException(ignoredExceptions);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
private static void ProcessDataInParallel(byte[] data)
// Use ConcurrentQueue to enable safe enqueueing from multiple threads.
var exceptions = new ConcurrentQueue<Exception>();
// Execute the complete loop and capture all exceptions.
Parallel.ForEach(data, d =>
// Cause a few exceptions, but not too many.
if (d < 3) throw new ArgumentException($"Value is {d}. Value must be greater than or equal to 3.");
else Console.Write(d + " ");
// Store the exception and continue with the loop.
catch (Exception e)
exceptions.Enqueue(e);
Console.WriteLine();
// Throw the exceptions here after the loop completes.
if (!exceptions.IsEmpty)
throw new AggregateException(exceptions);
' How to: Handle Exceptions in Parallel Loops
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading.Tasks
Module ExceptionsInLoops
Sub Main()
' Create some random data to process in parallel.
' There is a good probability this data will cause some exceptions to be thrown.
Dim data(1000) As Byte
Dim r As New Random()
r.NextBytes(data)
ProcessDataInParallel(data)
Catch ae As AggregateException
Dim ignoredExceptions As New List(Of Exception)
' This is where you can choose which exceptions to handle.
For Each ex As Exception In ae.Flatten().InnerExceptions
If (TypeOf (ex) Is ArgumentException) Then
Console.WriteLine(ex.Message)
ignoredExceptions.Add(ex)
End If
If ignoredExceptions.Count > 0 Then
Throw New AggregateException(ignoredExceptions)
End If
End Try
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Sub ProcessDataInParallel(ByVal data As Byte())
' Use ConcurrentQueue to enable safe enqueueing from multiple threads.
Dim exceptions As New ConcurrentQueue(Of Exception)
' Execute the complete loop and capture all exceptions.
Parallel.ForEach(Of Byte)(data, Sub(d)
' Cause a few exceptions, but not too many.
If d < 3 Then
Throw New ArgumentException($"Value is {d}. Value must be greater than or equal to 3")
Console.Write(d & " ")
End If
Catch ex As Exception
' Store the exception and continue with the loop.
exceptions.Enqueue(ex)
End Try
End Sub)
Console.WriteLine()
' Throw the exceptions here after the loop completes.
If exceptions.Count > 0 Then
Throw New AggregateException(exceptions)
End If
End Sub
End Module
PLINQ 和 TPL 中的 Lambda 表达式