Дескрипторы ожидания и пространство имен System.Threading.Tasks - PullRequest
2 голосов
/ 23 февраля 2012

Когда я использую Parallel.ForEach или Parallel.For в пространстве имен System.Threading.Tasks, могу ли я предположить, что все потоки синхронизируются до продолжения выполнения?

Есть ли что-то, эквивалентное

WaitHandle.WaitAll(...);

происходит?

Так что, если я позвоню что-то вроде

Parallel.ForEach(collection, DoSomethingWithObject);

Можно ли быть уверенным, что каждый вызов DoSomethingWithObject завершен до того, как ForEach вернется, или мне нужно использовать WaitHandles сам?

Ответы [ 4 ]

3 голосов
/ 23 февраля 2012

Чтобы расширить правильный ответ Фонга, Parallel.For и Parallel.ForEach внутренне создают так называемый ParallelXXXReplicationTask, который запускается синхронно и порождает X число дочерних задач, где X - эффективное количество уровней параллелизма (по умолчанию Environment.ProcessorCount). Каждая дочерняя задача синхронизируется с Semphore, который освобождает родительскую задачу после установки (счетчик до 0), что гарантирует, что выполнение родительской задачи будет возвращаться только после завершения всех дочерних задач (или сбоя / остановки, что определяется с помощью синхронизированных настроек). Так как parentTask запускается синхронно и находится в ожидании. Вы можете убедиться, что всякий раз, когда ваш вызов метода Parallel возвращается, все итерации были эффективно завершены.

2 голосов
/ 23 февраля 2012

Могу ли я быть уверен, что каждый вызов DoSomethingWithObject завершен до того, как ForEach вернется, или мне нужно использовать WaitHandles самостоятельно?

Parallel.ForEach является блокирующим вызовом.Он не вернется, пока не будет завершена каждая итерация.

Есть ли что-то эквивалентное WaitHandle.WaitAll(...);?

Да, более или менее.На самом деле он не будет использовать WaitHandle.WaitAll, потому что 1) он будет ужасно неэффективным и 2) он не масштабируется, поскольку имеет ограничение в 64 дескриптора.Есть несколько очень масштабируемых методов для ожидания выполнения нескольких задач.Один из моих любимых - использовать CountdownEvent. 1

Вот как это работает.Используйте свое воображение и притворяйтесь, что Parallel.ForEach превращается в следующий код. 2

var finished = new CountdownEvent(1);
foreach (var item in collection)
{
  var capture = item;
  finished.AddCount();
  Task.Factory.StartNew(
    () =>
    {
      try
      {
        DoSomething(capture);
      }
      finally
      {
        finished.Signal();
      }
    });
}
finished.Signal();
finished.Wait();

1 Я не говорю, что это используемая техникана Parallel.ForEach, но, вероятно, что-то похожее.

2 На самом деле Parallel.ForEach реализовано гораздо более сложным образом.Я только пытаюсь помочь вам представить, как он может ждать завершения каждой итерации.

2 голосов
/ 23 февраля 2012

Все задачи будут выполнены к моменту возврата Parallel.ForEach(), если только вызов Stop() не был специально сделан для прерывания параллельного выполнения. В таких случаях свойство .IsCompleted объекта ParallelLoopState, возвращаемого Parallel.ForEach(), будет false.

Вы можете прочитать об этом здесь:

http://msdn.microsoft.com/en-us/library/dd992001.aspx

http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallelloopresult.aspx

Вы также можете написать небольшое тестовое приложение, в котором DoSomethingWithObject() - очень длительная операция или вызов Thread.Sleep(), чтобы проверить это. Выполнение будет блокироваться до тех пор, пока все потоки не перестанут спать.

Пример:

Parallel.ForEach(Enumerable.Range(1, 8),
    i =>
    {
        Thread.Sleep(5000);
        Console.WriteLine(i + " done!");
    });
Console.WriteLine("All done!");
0 голосов
/ 03 марта 2012

Parallel.ForEach() и Parallel.For() будут блокироваться до тех пор, пока все его задачи не будут завершены, либо потому, что они выполнены успешно, либо потому, что они были отменены. Так что да, все потоки синхронизируются перед продолжением выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...