Pisahkan paralel. Jarak?

111

Bagaimana cara keluar dari loop parallel.for ?

Saya memiliki pernyataan yang cukup rumit yang terlihat seperti berikut:

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

Menggunakan kelas paralel, saya dapat mengoptimalkan proses ini sejauh ini. Namun; Saya tidak tahu cara memutus loop paralel? The break;pernyataan melempar kesalahan berikut sintaks:

Tidak ada loop penutup yang akan diputus atau dilanjutkan

Rasmus Søborg
sumber
1
Apakah Anda mengharapkan SEMUA instance paralel dari loop break pada saat yang sama?
n8wrl

Jawaban:

185

Gunakan ParallelLoopState.Breakmetode:

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

Atau dalam kasus Anda:

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();
        }
    }));
Tudor
sumber
persis. akan memposting ini sendiri.
Mare Infinitus
1
Memikirkan perulangan foreach berurutan, dijamin bahwa item sebelum item yang karena alasan apa pun menyebabkan jeda diproses. Bagaimana dengan Parallel.ForEach yang urutan itemnya tidak harus sesuai urutan pemrosesannya? Apakah dijamin juga bahwa semua item dalam IEnumerable <...> sebelum item yang memanggil state.Break () sedang diproses dan yang datang setelahnya tidak? Meskipun yang pertama bisa dicapai entah bagaimana, saya tidak melihat bagaimana yang terakhir bisa dicapai sama sekali.
Hendrik Wiese
4
@ Hendrik Wiese: Dokumen mengatakan: 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.danthere is no guarantee that iterations after the current one will definitely not execute.
Tudor
2
jadi akan state.Stop()lebih tepat untuk secara andal mencapai hasil yang diharapkan, seperti yang disebutkan di bawah ini oleh Mike Perrenoud dan MBentley
xtreampb
44

Anda melakukan ini dengan memanggil menggunakan overload dari Parallel.Foratau Parallel.ForEachyang lewat dalam keadaan loop, lalu memanggil ParallelLoopState.Breakatau ParallelLoopState.Stop. Perbedaan utama adalah pada seberapa cepat hal-hal rusak - dengan Break(), loop akan memproses semua item dengan "indeks" yang lebih awal daripada saat ini. Dengan Stop(), itu akan keluar secepat mungkin.

Untuk detailnya, lihat Cara: Berhenti atau Putus dari Paralel . Untuk Loop .

Reed Copsey
sumber
3
+1, sepertinya beberapa dari kita di sini memiliki jawaban yang persis sama :) - oh, dan saya mendukung Anda untuk memberikan komentar yang lain.
Mike Perrenoud
Terima kasih atas penjelasannya. Apakah Anda tahu kapan break atau stop dipanggil, apakah iterasi yang saat ini sedang dieksekusi selesai atau apakah iterasi tersebut berhenti di tengah eksekusi?
CeejeeB
1
@CeejeeB Saat ini menjalankan operasi selesai.
Reed Copsey
12

Apa yang harus Anda gunakan adalah Any, bukan loop foreach:

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

Any cukup pintar untuk berhenti begitu mengetahui bahwa hasilnya pasti benar.

Pelayanan
sumber
10

LoopState tentu saja merupakan jawaban yang bagus. Saya menemukan jawaban sebelumnya memiliki begitu banyak hal lain sehingga sulit untuk melihat jawabannya, jadi inilah kasus sederhana:

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.
});
MBentley
sumber
5

Gunakan saja loopStateyang bisa disediakan.

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

Lihat artikel MSDN ini sebagai contoh.

Mike Perrenoud
sumber