Saltar al contenido

Parallel.Foreach c# ¿Función de pausa y detención?

Nuestros desarrolladores estrellas han agotado sus reservas de café, por su búsqueda noche y día por la resolución, hasta que Benjamín halló el hallazgo en Gitea y hoy la comparte contigo.

Solución:

Damien_The_Unbeliver tiene un buen método, pero eso es solo si desea que algún proceso externo detenga el ciclo. Si desea que el bucle se rompa como si usara un break en una normalidad for o foreach bucle necesitará usar una sobrecarga que tenga un ParallelLoopState como uno de los parámetros del cuerpo del bucle. ParallelLoopState tiene dos funciones que son relevantes para lo que quieres hacer, Stop() y Break().

La función Stop() dejará de procesar elementos a la mayor conveniencia del sistema lo que significa que se pueden realizar más iteraciones después de llamar a Stop() y no se garantiza que los elementos que vinieron antes del elemento en el que se detuvo hayan comenzado a procesarse.

La función Break() funciona exactamente igual que Stop() sin embargo, también evaluará todos los elementos del IEnumerable que vino antes del artículo que llamaste Break() sobre. Esto es útil cuando no le importa en qué orden se procesan los elementos, pero debe procesar todos los elementos hasta el punto en que se detuvo.

Inspeccione el ParallelLoopResult devuelto por el foreach para ver si el foreach se detuvo antes y si usó Break()cuál es el artículo con el número más bajo que procesó.

Parallel.ForEach(list, (item, loopState) =>
    
        bool endEarly = doStuff(item);
        if(endEarly)
        
            loopState.Break();
        
    
    );
//Equivalent to the following non parallel version, except that if doStuff ends early
//    it may or may not processed some items in the list after the break.
foreach(var item in list)

    bool endEarly = doStuff(item);
    if(endEarly)
    
        break;
    


Aquí hay un ejemplo más práctico.

static bool[] list = new int[]false, false, true, false, true, false;

long LowestElementTrue()

    ParallelLoopResult result = Parallel.ForEach(list, (element, loopState) =>
    
        if(element)
            loopState.Break();
    
    if(result.LowestBreakIteration.IsNull)
        return -1;
    else
        return result.LowestBreakIteration.Value;
   

No importa cómo divida el trabajo, siempre devolverá 2 como respuesta.

digamos que el procesador envía dos subprocesos para procesar esto, el primer subproceso procesa los elementos 0-2 y el segundo subproceso procesa los elementos 3-5.

Thread 1:                Thread 2
0, False, continue next  3, False, continue next
1, False, continue next  4, True, Break
2, True, Break           5, Don't process Broke

Ahora, el índice más bajo desde el que se llamó Break fue 2, por lo que ParallelLoopResult.LowestBreakIteration devolverá 2 cada vez, sin importar cómo se dividan los subprocesos, ya que siempre se procesará hasta el número 2.

Aquí hay un ejemplo de cómo se podría usar Stop.

static bool[] list = new int[]false, false, true,  false, true, false;

long FirstElementFoundTrue()

    long currentIndex = -1;
    ParallelLoopResult result = Parallel.ForEach(list, (element, loopState, index) =>
    
        if(element)
        
             loopState.Stop();

             //index is a 64 bit number, to make it a atomic write
             // on 32 bit machines you must either:
             //   1. Target 64 bit only and not allow 32 bit machines.
             //   2. Cast the number to 32 bit.
             //   3. Use one of the Interlocked methods.
             Interlocked.Exchange (ref currentIndex , index);
        
    
    return currentIndex;
   

Dependiendo de cómo divida el trabajo, devolverá 2 o 4 como respuesta.

digamos que el procesador envía dos subprocesos para procesar esto, el primer subproceso procesa los elementos 0-2 y el segundo subproceso procesa los elementos 3-5.

Thread 1:                 Thread 2
0, False, continue next    3, False, continue next
1, False, continue next    4, True, Stop
2, Don't process, Stopped  5, Don't process, Stopped

En este caso devolverá 4 como respuesta. Veamos el mismo proceso pero si procesa todos los demás elementos en lugar de 0-2 y 3-5.

Thread 1:                   Thread 2
0, False, continue next     1, False, continue next
2, True, Stop               3, False, continue next
4, Don't process, Stopped   5, Don't process, Stopped

Esta vez devolverá 2 en lugar de 4.

Para poder parar un Parallel.ForEachpuede usar una de las sobrecargas que acepta un ParallelOptions parámetro e incluir un CancellationToken en esas opciones.

Ver Cancelación para más detalles.

Como para haciendo una pausa, No puedo pensar por qué querrías hacer eso, en general. Es posible que esté buscando una Barrera (que se usa para coordinar esfuerzos entre múltiples subprocesos, por ejemplo, si todos necesitan completar la parte A antes de continuar con la parte B), pero no creo que la use con Parallel.ForEachya que no sabes cuántos participantes habrá.

Recuerda que puedes mostrar este ensayo si te ayudó.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *