¿Cuál sería la forma más efectiva de pausar y detener (antes de que termine) parallel.foreach?Parallel.Foreach C# Pausa y función de parada?
Parallel.ForEach(list, (item) =>
{
doStuff(item);
});
¿Cuál sería la forma más efectiva de pausar y detener (antes de que termine) parallel.foreach?Parallel.Foreach C# Pausa y función de parada?
Parallel.ForEach(list, (item) =>
{
doStuff(item);
});
Damien_The_Unbeliver tiene un buen método, pero eso es solo si desea tener algún proceso externo para detener el ciclo. Si desea que el bucle salga como si fuera break
en un bucle normal for
o foreach
, necesitará usar a overload que tenga un ParallelLoopState
como uno de los parámetros del cuerpo del bucle. ParallelLoopState
tiene dos funciones que son relevantes para lo que quiere hacer, Stop()
y Break()
.
La función Stop()
dejará de elementos de procesamiento a la mayor brevedad posible del sistema de que significa que más iteraciones se podrían realizar después de llamar a la parada() y no se garantiza que los elementos que vinieron antes que el elemento que se detuvo en incluso han comenzado para procesar.
La función Break()
realiza exactamente igual que Stop()
sin embargo, también evaluará todos los elementos del IEnumerable
que vinieron antes del elemento al que se llamó en Break()
. Esto es útil para cuando no le importa en qué orden se procesan los elementos, pero debe procesar todos los elementos hasta el punto que detuvo.
Inspeccione el ParallelLoopResult devuelto desde 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í es 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 la forma en que se divide el trabajo que siempre devolverá 2 como respuesta.
Digamos que el procesador distribuye dos hilos para procesar esto, el primer hilo procesa los elementos 0-2 y el segundo hilo 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 la rotura menor índice fue llamado desde 2 era tan ParallelLoopResult.LowestBreakIteration
devolverá 2 cada vez, no importa cuan-los hilos se rompen, ya que siempre se procesará hasta el número 2.
Aquí un ejemplo de cómo podría usarse 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;
}
Según cómo se divida el trabajo, devolverá 2 o 4 como respuesta.
Digamos que el procesador distribuye dos hilos para procesar esto, el primer hilo procesa los elementos 0-2 y el segundo hilo 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 cualquier otro elemento 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 se volverá 2 en lugar de 4.
Para ser capaz de detener un Parallel.ForEach
, puede utilizar una de las sobrecargas que acepta un parámetro ParallelOptions
, e incluir una CancellationToken
en esas opciones.
Consulte Cancellation para obtener más información.
En cuanto a pausando, no puedo pensar por qué querrías hacer eso, en general. Es posible que esté buscando un Barrier (que se utiliza para coordinar esfuerzos entre varios hilos, por ejemplo, si todos deben completar la parte A antes de continuar con la parte B), pero no creo que lo use con Parallel.ForEach
, ya que usted no sabe cuántos participantes habrá.
Pausa? ¿Por qué querrías detenerlo? –
Pausa es solo una característica adicional que quería agregar si es posible, por supuesto. Estoy escribiendo un programa que tiene mucha CPU y conexión a Internet y puede llenarlo rápidamente para que una pausa no sea tan mala. Voy a implementar la funcionalidad de detención y guardar la lista de elementos sin terminar en otra lista y luego en la siguiente ejecución reescribir esa lista. Y continuar desde donde está parado. Un poco como pausa Gracias. – bbrez1
Si una de las respuestas le dio una solución [debe marcar esa respuesta como aceptada] (http://stackoverflow.com/faq#howtoask). –