Romper el paralelo. ¿Cada uno?


111

¿Cómo salgo de un ciclo for paralelo ?

Tengo una declaración bastante compleja que se parece a la siguiente:

Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),
    new Action<ColorIndexHolder>((ColorIndexHolder Element) =>
    {
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I)
        {
            Found = true;
            break;
        }
    }));

Usando la clase paralela, puedo optimizar este proceso por mucho. Sin embargo; ¿No puedo averiguar cómo romper el bucle paralelo? La break;declaración arroja el siguiente error de sintaxis:

Sin bucles de cierre de los cuales romper o continuar


1
¿Esperaría que TODAS las instancias paralelas del bucle se rompan al mismo tiempo?
n8wrl

Respuestas:


185

Usa el ParallelLoopState.Breakmétodo:

 Parallel.ForEach(list,
    (i, state) =>
    {
       state.Break();
    });

O en tu caso:

Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),
    new Action<ColorIndexHolder, ParallelLoopState>((ColorIndexHolder Element, ParallelLoopState state) =>
    {
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I)
        {
            Found = true;
            state.Break();
        }
    }));

exactamente. estaba a punto de publicar esto yo mismo.
Mare Infinitus

1
Pensando en un ciclo foreach secuencial, se garantiza que los elementos antes del elemento que por cualquier motivo causaron la ruptura se procesen. ¿Qué pasa con Parallel.ForEach donde el orden de los artículos no tiene que ser necesariamente el orden en el que se procesan? ¿Está también garantizado que todos los elementos de un IEnumerable <...> antes del que invoca state.Break () se están procesando y los que vienen después no? Aunque lo primero podría lograrse de alguna manera, no veo cómo lo segundo sería posible en absoluto.
Hendrik Wiese

4
@Hendrik Wiese: Los doctores dicen: Calling the Break method informs the for operation that iterations after the current one don't have to execute. However, all iterations before the current one will still have to be executed if they haven't already.ythere is no guarantee that iterations after the current one will definitely not execute.
Tudor

2
entonces sería state.Stop()más apropiado lograr de manera confiable los resultados esperados, como lo mencionan a continuación Mike Perrenoud y MBentley
xtreampb

44

Para hacer esto, llame usando la sobrecarga de Parallel.Foro Parallel.ForEachque pasa en un estado de bucle, luego llame a ParallelLoopState.Breako ParallelLoopState.Stop. La principal diferencia está en la rapidez con la que se rompen las cosas: con Break()el ciclo, el ciclo procesará todos los elementos con un "índice" anterior al actual. Con Stop(), saldrá lo más rápido posible.

Para obtener más información, consulte Cómo: detener o romper un bucle paralelo .


3
+1, parece que algunos de nosotros aquí tenemos exactamente la misma respuesta :) - Ah, y te apoyé en ese otro comentario.
Mike Perrenoud

Gracias por esta explicacion. ¿Sabe cuándo se llama a break o stop? ¿Es el caso de que las iteraciones que se están ejecutando actualmente se completan o detiene las iteraciones a mitad de la ejecución?
CeejeeB

1
@CeejeeB Actualmente se están ejecutando las operaciones completadas.
Reed Copsey

12

Lo que debería usar es Any, en lugar de un bucle foreach:

bool Found = ColorIndex.AsEnumerable().AsParallel()
    .Any(Element => Element.StartIndex <= I 
      && Element.StartIndex + Element.Length >= I);

Any es lo suficientemente inteligente como para detenerse tan pronto como sepa que el resultado debe ser cierto.


10

LoopState es sin duda una gran respuesta. Descubrí que las respuestas anteriores tenían muchas otras cosas que era difícil ver la respuesta, así que aquí hay un caso simple:

using System.Threading.Tasks;

Parallel.ForEach(SomeTable.Rows(), (row, loopState) =>
{
    if (row.Value == testValue)
    {
        loopState.Stop();  // Stop the ForEach!
    }       
    // else do some other stuff here.
});

5

Solo use el loopStateque se puede proporcionar.

Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),  
    new Action<ColorIndexHolder>((Element, loopState) => { 
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I) { 
            loopState.Stop();
        }     
})); 

Consulte este artículo de MSDN para ver un ejemplo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.