Freigeben über


Gewusst wie: Abbrechen einer Parallel.For-Schleife oder einer ForEach-Schleife

Die Parallel.For-Methode und Parallel.ForEach-Methode unterstützen einen Abbruch durch die Verwendung von Abbruchtoken. Weitere allgemeine Informationen zum Abbruch finden Sie unter Abbruch. In einer parallelen Schleife geben Sie das CancellationToken für die Methode im ParallelOptions-Parameter an und schließen dann den parallelen Aufruf in einen try/catch-Block ein.

Beispiel

Im folgenden Beispiel wird veranschaulicht, wie Sie einen Aufruf von Parallel.ForEach abbrechen. Sie können den gleichen Ansatz auch auf einen Parallel.For-Aufruf anwenden.

' How to: Cancel a Parallel.For or ForEach Loop

Imports System.Threading
Imports System.Threading.Tasks

Module CancelParallelLoops

    Sub Main()

        Dim nums() As Integer = Enumerable.Range(0, 10000000).ToArray()
        Dim cts As New CancellationTokenSource

         ' Use ParallelOptions instance to store the CancellationToken
        Dim po As New ParallelOptions
        po.CancellationToken = cts.Token
        po.MaxDegreeOfParallelism = System.Environment.ProcessorCount
        Console.WriteLine("Press any key to start. Press 'c' to cancel.")
        Console.ReadKey()

        ' Run a task so that we can cancel from another thread.
        Dim t As Task = Task.Factory.StartNew(Sub()
                                                  If Console.ReadKey().KeyChar = "c"c Then
                                                      cts.Cancel()
                                                  End If
                                                  Console.WriteLine(vbCrLf & "Press any key to exit.")
                                              End Sub)

        Try

            ' The error "Exception is unhandled by user code" will appear if "Just My Code" 
            ' is enabled. This error is benign. You can press F5 to continue, or disable Just My Code.
            Parallel.ForEach(nums, po, Sub(num)
                                           Dim d As Double = Math.Sqrt(num)
                                           Console.CursorLeft = 0
                                           Console.Write("{0:##.##} on {1}", d, Thread.CurrentThread.ManagedThreadId)
                                           po.CancellationToken.ThrowIfCancellationRequested()
                                       End Sub)

        Catch e As OperationCanceledException
            Console.WriteLine(e.Message)
        End Try

        Console.ReadKey()

    End Sub
End Module
namespace CancelParallelLoops
{
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static void Main()
        {
            int[] nums = Enumerable.Range(0, 10000000).ToArray();
            CancellationTokenSource cts = new CancellationTokenSource();

           // Use ParallelOptions instance to store the CancellationToken
            ParallelOptions po = new ParallelOptions();
            po.CancellationToken = cts.Token;
            po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
            Console.WriteLine("Press any key to start. Press 'c' to cancel.");
            Console.ReadKey();

            // Run a task so that we can cancel from another thread.
            Task.Factory.StartNew(() =>
            {
                if (Console.ReadKey().KeyChar == 'c')
                    cts.Cancel();
                Console.WriteLine("press any key to exit");
            });

            try
            {
                Parallel.ForEach(nums, po, (num) =>
                {
                    double d = Math.Sqrt(num);
                    Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
                    po.CancellationToken.ThrowIfCancellationRequested();
                });
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadKey();
        }
    }
}

Wenn das Token, das den Abbruch signalisiert, das gleiche Token wie in der ParallelOptions-Instanz ist, löst die parallele Schleife beim Abbruch eine einzelne OperationCanceledException aus. Wenn ein anderes Token einen Abbruch verursacht, löst die Schleife eine AggregateException mit einer OperationCanceledException als InnerException aus.

Siehe auch

Konzepte

Datenparallelität (Task Parallel Library)

Lambda-Ausdrücke in PLINQ und TPL