2015-10-03 4 views
3

Я создал список Task, как это:Как работает Task.WaitAll()?

public void A() 
{ 

} 

public void B() 
{ 

} 

public void C() 
{ 

} 

public void Ex() 
{ 
    Task.WaitAll(Task.Factory.StartNew(A), Task.Factory.StartNew(B), Task.Factory.StartNew(C)); 
    var p=true; 
} 

Теперь мой вопрос заключается в том, что. Будут ли все задачи внутри списка выполняться один за другим или будут выполняться параллельно.

р = истина

«р» устанавливается, когда все задачи выполнены или, прежде чем они сделаны?

ответ

6

Для первого вопроса:

Будут ли эти задачи выполнить по одному или асинхронно.

(здесь, я полагаю, вы имели в виду одновременно, который не является точно такой же)

Использование StartNew будет запускать задачу в текущем TaskScheduler. по умолчанию это означает, что он будет использовать ThreadPool, и, если в пуле потоков есть доступные слоты, он будет запускаться параллельно. Если все слоты берутся в пуле задач, это может затормозить выполнение задач, чтобы избежать перегрузки процессора, и задачи могут не выполняться одновременно одновременно: никаких гарантий нет.

Это упрощенное объяснение, а более полное и подробное объяснение стратегии планирования - explained on the TaskScheduler documentation.

В качестве примечания стороны. В documentation for StartTask упоминается тонкая разница между StartNew(Action) и Run(Action). Они не совсем эквивалентны, в отличие от других ответов.

Начиная с .NET Framework 4.5, вы можете использовать метод Task.Run (Action) как быстрый способ вызвать StartNew (Action) с параметрами по умолчанию. Обратите внимание, однако, что существует разница в поведении между двумя методами: Task.Run (Action) по умолчанию не позволяет дочерние задачи запускаться с параметром TaskCreationOptions.AttachedToParent для присоединения к текущему экземпляру Task, тогда как StartNew (Action) делает.

Что касается второго вопроса

«р» устанавливается, когда все задачи выполнены или, прежде чем они сделаны?

Короткий ответ: да.

Однако вам следует подумать об использовании другого подхода, поскольку этот блок заблокирует ваш поток и будет ждать бездействия. Альтернативой является предоставление контроля обратно вызывающему, если вы можете, и поэтому поток освобождается и может использоваться ЦП. это особенно верно, если поток, на котором работает этот код, является частью ThreadPool.

поэтому, вы должны предпочесть using WhenAll(). Она возвращает задачу, которая может быть долгожданной или на которых ContinueWith можно назвать

примером:

var tasks = new Task[] {Task.Factory.StartNew(A), Task.Factory.StartNew(B), Task.Factory.StartNew(C)}; 
await Task.WhenAll(tasks); 
+0

Вы, вероятно, имеете в виду 'ThreadPool' – i3arnon

+0

Абсолютно, мой плохой. TaskPool существует, но это концепция Reactive Extension. извините за путаницу. –

2

first: Вы создаете задачи неправильно. когда вы создаете экземпляр задачи, вам нужно вызвать метод Start, иначе он ничего не дозирует.

new Task(() => /* Something * /).Start(); 

если вы создаете задачи, как вы только что сделали (с помощью вызова конструктора и нажать старт или с помощью TaskFacotry или даже Task.Run) по умолчанию поток ThreadPool будет посвящен задаче и, таким образом, задача выполнена в параллели.

Метод Task.WhenAll блокирует выполнение метода вызова до тех пор, пока все выполняемые им задачи не будут выполнены.

поэтому логическая переменная задается после выполнения всех задач.

+1

Да я просто изменил его Task.Factory.StartNew (A). Это нормально ? –

+2

Да, но предпочтительный подход - использовать Task.Run, который более оптимизирован для большинства основных сценариев. – SHM

Смежные вопросы