แบ่งขนานไปข้างหน้า?


112

ฉันจะแยกออกจากเส้นขนานสำหรับลูปได้อย่างไร

ฉันมีข้อความที่ค่อนข้างซับซ้อนซึ่งมีลักษณะดังต่อไปนี้:

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

การใช้คลาสคู่ขนานฉันสามารถเพิ่มประสิทธิภาพกระบวนการนี้ได้ อย่างไรก็ตาม; ฉันคิดไม่ออกว่าจะทำลายลูปขนานได้อย่างไร? break;คำสั่งพ่นไวยากรณ์ผิดพลาดต่อไปนี้:

ไม่มีการปิดล้อมลูปที่จะทำลายหรือดำเนินการต่อ


1
คุณคาดหวังว่าอินสแตนซ์แบบขนานทั้งหมดของลูปจะแตกพร้อมกันหรือไม่
n8wrl

คำตอบ:


186

ใช้ParallelLoopState.Breakวิธีการ:

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

หรือในกรณีของคุณ:

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

เป๊ะ กำลังจะโพสต์สิ่งนี้ด้วยตัวเอง
Mare Infinitus

1
การคิดถึงการวนรอบ foreach ตามลำดับจะรับประกันได้ว่ารายการก่อนหน้ารายการที่ไม่ว่าด้วยเหตุผลใดก็ตามที่ทำให้เกิดการแบ่ง สิ่งที่เกี่ยวกับ ParallelForEach ที่คำสั่งซื้อของแต่ละรายการไม่จำเป็นต้องเป็นลำดับที่ประมวลผล? มีการรับประกันหรือไม่ว่ารายการทั้งหมดใน IEnumerable <... > ก่อนรายการที่เรียกใช้สถานะ Break () กำลังถูกประมวลผลและสิ่งที่ตามมาไม่ได้? แม้ว่าในอดีตจะประสบความสำเร็จ แต่ฉันก็ไม่เห็นว่าอย่างหลังจะเป็นไปได้อย่างไร
Hendrik Wiese

4
@Hendrik Wiese: เอกสารกล่าวว่า: 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.และthere is no guarantee that iterations after the current one will definitely not execute.
ทิวดอร์

2
ดังนั้นจึงstate.Stop()เหมาะสมกว่าที่จะบรรลุผลลัพธ์ที่คาดหวังไว้ได้อย่างน่าเชื่อถือดังที่ Mike Perrenoud และ MBentley กล่าวไว้ด้านล่าง
xtreampb

45

คุณทำเช่นนี้โดยการเรียกใช้เกินพิกัดของParallel.ForหรือParallel.ForEachที่ผ่านไปในรัฐห่วงแล้วโทรหรือParallelLoopState.Break ParallelLoopState.Stopความแตกต่างที่สำคัญคือความเร็วในการทำลายสิ่งต่าง ๆ โดยBreak()ลูปจะประมวลผลรายการทั้งหมดที่มี "ดัชนี" ก่อนหน้ากว่าปัจจุบัน ด้วยStop()มันจะออกโดยเร็วที่สุด

ดูรายละเอียดวิธีการ: หยุดหรือทำลายจาก Parallel.For ห่วง


3
+1 ดูเหมือนว่าพวกเราสองสามคนที่นี่จะมีคำตอบเหมือนกัน :) - โอ้และฉันได้สำรองข้อมูลของคุณไว้ที่นั่นในคอมเมนต์คนอื่น
Mike Perrenoud

ขอบคุณสำหรับคำอธิบายนี้ คุณรู้หรือไม่ว่าเมื่อใดที่เรียกว่า break หรือ stop เป็นกรณีที่การทำซ้ำที่ดำเนินการอยู่ในปัจจุบันเสร็จสมบูรณ์หรือหยุดการทำซ้ำระหว่างการดำเนินการหรือไม่
CeejeeB

1
@CeejeeB ขณะนี้การดำเนินการเสร็จสมบูรณ์
Reed Copsey

12

สิ่งที่คุณควรใช้คือAnyแทนที่จะใช้ foreach loop:

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

Any ฉลาดพอที่จะหยุดทันทีที่รู้ว่าผลลัพธ์ต้องเป็นจริง


10

LoopState เป็นคำตอบที่ดีอย่างแน่นอน ฉันพบว่าคำตอบก่อนหน้านี้มีสิ่งอื่น ๆ มากมายซึ่งยากที่จะเห็นคำตอบดังนั้นนี่เป็นกรณีง่ายๆ:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.