Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les surcharges Parallel.For et Parallel.ForEach ne possèdent pas de mécanisme permettant de gérer les exceptions. En cela, elles sont similaires aux boucles for
et foreach
normales (For
et For Each
en Visual Basic). Une exception non gérée provoque l’arrêt de la boucle dès que toutes les itérations qui s’exécutent en même temps sont terminées.
Quand vous ajoutez votre propre logique de gestion des exceptions à des boucles parallèles, gérez le cas dans lequel de telles exceptions peuvent être levées simultanément sur plusieurs threads et le cas dans lequel une exception levée sur un thread provoque la levée d'une autre exception sur un autre thread. Vous pouvez gérer les deux cas en encapsulant toutes les exceptions de la boucle dans un System.AggregateException. L'exemple suivant montre une méthode possible.
Notes
Quand l’option « Uniquement mon code » est activée, Visual Studio, dans certains cas, peut s’arrêter sur la ligne qui lève l’exception et afficher un message d’erreur indiquant que l’exception n’est pas gérée par le code utilisateur. Cette erreur est sans gravité. Vous pouvez appuyer sur F5 pour continuer et voir le comportement de gestion des exceptions qui est illustré dans l'exemple ci-dessous. Pour empêcher Visual Studio de s'arrêter sur la première erreur, il suffit de désactiver la case à cocher Uniquement mon code sous Outils, Options, Débogage, Général.
Exemple
Dans cet exemple, toutes les exceptions sont interceptées, puis encapsulées dans une System.AggregateException qui est ensuite levée. L'appelant peut décider des exceptions à gérer.
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);
try
{
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 =>
{
try
{
// 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)
Try
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)
Else
ignoredExceptions.Add(ex)
End If
Next
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)
Try
' 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")
Else
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