Compartir a través de


Cómo: Cancelar un bucle Parallel.For o ForEach

Los métodos Parallel.ForEach y Parallel.For admiten la cancelación a través del uso de tokens de cancelación. Para obtener más información sobre la cancelación en general, vea Cancelación. En un bucle paralelo, se proporciona CancellationToken al método en el parámetro ParallelOptions y después se agrega la llamada paralela en un bloque try-catch.

Ejemplo

En el ejemplo siguiente se muestra cómo cancelar una llamada a Parallel.ForEach. Puede aplicar el mismo enfoque a una llamada Parallel.For.

' 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();
        }
    }
}

Si el token que señala la cancelación es el mismo que se especifica en la instancia de ParallelOptions, el bucle paralelo producirá una OperationCanceledException única en la cancelación. Si algún otro token produce la cancelación, el bucle producirá una AggregateException con OperationCanceledException como InnerException.

Vea también

Conceptos

Paralelismo de datos (Task Parallel Library)

Expresiones lambda en PLINQ y TPL