Разрыв parallel.foreach?

112

Как мне выйти из цикла parallel.for ?

У меня есть довольно сложное утверждение, которое выглядит следующим образом:

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, мы гарантируем, что элементы перед элементом, который по какой-либо причине вызвал разрыв, будут обработаны. А как насчет Parallel.ForEach, где порядок элементов не обязательно должен совпадать с порядком их обработки? Гарантируется ли также, что все элементы в IEnumerable <...> перед тем, который вызывает state.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.
Tudor
2
так что тогда было state.Stop()бы более подходящим для надежного достижения ожидаемых результатов, как указано ниже Майком Перренудом и MBentley
xtreampb
45

Вы делаете это, вызывая с помощью перегрузки Parallel.Forили, Parallel.ForEachкоторая переходит в состояние цикла, а затем вызываяParallelLoopState.Break или ParallelLoopState.Stop. Основное различие заключается в том, как быстро все прерывается - Break()цикл будет обрабатывать все элементы с более ранним "индексом", чем текущий. С Stop(), он выйдет как можно быстрее.

Дополнительные сведения см. В разделе Практическое руководство. Остановить параллельный цикл или выйти из него .

Рид Копси
источник
3
+1, похоже, что у некоторых из нас есть точно такой же ответ :) - о, и я получил вашу поддержку там на том другом комментаторе.
Майк Перрено,
Спасибо за это объяснение. Знаете ли вы, когда вызывается либо break, либо stop, это тот случай, когда выполняемые в данный момент итерации завершены, или он останавливает итерации в середине выполнения?
CeejeeB
1
@CeejeeB Выполняемые операции завершены.
Рид Копси
12

Вы должны использовать Any, а не цикл foreach:

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

Any достаточно умен, чтобы остановиться, как только узнает, что результат должен быть верным.

Servy
источник
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.
});
MBentley
источник
5

Просто используйте то, loopStateчто может быть предоставлено.

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

Взгляните на эту статью MSDN для примера.

Майк Перрено
источник