Rompere parallel.foreach?


111

Come posso uscire da un ciclo parallel.for ?

Ho un'affermazione piuttosto complessa che assomiglia alla seguente:

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

Usando la classe parallela, posso ottimizzare questo processo di gran lunga. Però; Non riesco a capire come rompere il ciclo parallelo? L' break;istruzione genera il seguente errore di sintassi:

Nessun anello chiuso da cui interrompere o continuare


1
Ti aspetteresti che TUTTE le istanze parallele del ciclo si interrompano contemporaneamente?
n8wrl

Risposte:


185

Usa il ParallelLoopState.Breakmetodo:

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

O nel tuo 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();
        }
    }));

Esattamente. stavo per postarlo io stesso.
Mare Infinitus

1
Pensando a un ciclo foreach sequenziale è garantito che gli elementi prima dell'elemento che per qualsiasi motivo abbia causato l'interruzione vengano elaborati. Che dire di Parallel.ForEach in cui l'ordine degli articoli non deve necessariamente corrispondere all'ordine in cui vengono elaborati? È anche garantito che tutti gli elementi in un IEnumerable <...> prima di quello che richiama state.Break () vengono elaborati e quelli successivi non lo sono? Sebbene il primo possa essere ottenuto in qualche modo, non vedo come il secondo sarebbe affatto possibile.
Hendrik Wiese

4
@Hendrik Wiese: Docs say: 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.andthere is no guarantee that iterations after the current one will definitely not execute.
Tudor

2
quindi sarebbe state.Stop()più appropriato ottenere in modo affidabile i risultati attesi, come indicato di seguito da Mike Perrenoud e MBentley
xtreampb

44

Puoi farlo chiamando usando l'overload di Parallel.Foro Parallel.ForEachche passa in uno stato di ciclo, quindi chiamando ParallelLoopState.Breako ParallelLoopState.Stop. La differenza principale sta nella rapidità con cui le cose si interrompono: con Break(), il ciclo elaborerà tutti gli elementi con un "indice" precedente a quello corrente. Con Stop(), uscirà il più rapidamente possibile.

Per i dettagli, vedere Procedura: interrompere o interrompere un ciclo Parallel.For .


3
+1, sembra che alcuni di noi qui abbiano la stessa identica risposta :) - oh e ho avuto la tua schiena su quell'altro uomo dei commenti.
Mike Perrenoud

Grazie per questa spiegazione. Sai quando vengono chiamati break o stop, è il caso che le iterazioni attualmente in esecuzione siano completate o interrompe le iterazioni a metà dell'esecuzione?
CeejeeB

1
@CeejeeB Operazioni attualmente in esecuzione completate.
Reed Copsey

12

Quello che dovresti usare è Any, piuttosto che un ciclo foreach:

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

Any è abbastanza intelligente da fermarsi non appena sa che il risultato deve essere vero.


10

LoopState è sicuramente un'ottima risposta. Ho scoperto che le risposte precedenti contenevano così tante altre cose che era difficile vedere la risposta, quindi ecco un semplice caso:

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

Basta usare quello loopStateche può essere fornito.

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

Guarda questo articolo di MSDN per un esempio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.