Запуск нескольких асинхронных задач и ожидание их завершения
Мне нужно запустить несколько асинхронных задач в консольном приложении, и ждать их завершения перед дальнейшей обработкой.
там много статей, но я, кажется, все больше запутываюсь, чем больше читаю. Я прочитал и понял основные принципы библиотеки задач, но мне явно не хватает ссылки где-то.
Я понимаю, что можно цеплять задачи так, чтобы они начинались после завершения другого (что в значительной степени является сценарием для всех статьи, которые я читал), но я хочу, чтобы все мои задачи выполнялись одновременно, и я хочу знать, как только они все будут завершены.
какая самая простая реализация для такого сценария?
6 ответов:
в обоих ответах не упоминалось ожидаемое
Task.WhenAll
:var task1 = DoWorkAsync(); var task2 = DoMoreWorkAsync(); await Task.WhenAll(task1, task2);
основное различие между
Task.WaitAll
иTask.WhenAll
это то, что первый будет блокировать (аналогично использованиюWait
на одной задаче), в то время как последняя не будет и может быть ожидаема, отдавая контроль обратно вызывающему до завершения всех задач.более того, обработка исключений отличается:
Task.WaitAll
:по крайней мере один из экземпляров задачи был отменен-или-исключение было вызвано во время выполнения по крайней мере одного из экземпляров задачи. Если задача была отменена, AggregateException содержит OperationCanceledException в своей коллекции InnerExceptions.
Task.WhenAll
:если какая-либо из поставленных задач завершается в неисправном состоянии, возвращенная задача также завершится в неисправном состоянии, где ее исключения будут содержать агрегацию из набора развернутых исключений из каждой поставляемой задачи.
если ни одна из поставленных задач не была сброшена, но хотя бы одна из них была отменена, возвращенная задача завершится в отмененном состоянии.
если ни одна из задач не была сброшена и ни одна из задач не была отменена, результирующая задача завершится в состоянии RanToCompletion. Если предоставленный массив/перечисляемый не содержит задач, возвращенная задача немедленно перейдет в состояние RanToCompletion до он возвращается к звонящему.
вы можете создать много задач, таких как:
List<Task> TaskList = new List<Task>(); foreach(...) { var LastTask = new Task(SomeFunction); LastTask.Start(); TaskList.Add(LastTask); } Task.WaitAll(TaskList.ToArray());
лучший вариант, который я видел, это следующий метод расширения:
public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) { return Task.WhenAll(sequence.Select(action)); }
назовем это так:
await sequence.ForEachAsync(item => item.SomethingAsync(blah));
или с асинхронной лямбда:
await sequence.ForEachAsync(async item => { var more = await GetMoreAsync(item); await more.FrobbleAsync(); });
вы хотите, чтобы цепь
Task
s, или они могут быть вызваны параллельно?объединение
Просто сделайте что-то вродеTask.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...); Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
и не забудьте проверить предыдущие
Task
экземпляра в каждомContinueWith
как это может быть нарушенными.для параллельного образом
Самый простой метод, с которым я столкнулся:Parallel.Invoke
В противном случае естьTask.WaitAll
или вы даже можете использоватьWaitHandle
s для выполнения обратного отсчета до нуля действий слева (подождите, есть новый класс:CountdownEvent
), или ...
можно использовать
WhenAll
который вернет ожидаемыйTask
илиWaitAll
который не имеет возвращаемого типа и будет блокировать дальнейшее выполнение кода simular toThread.Sleep
пока все задачи не будут выполнены, отменены или неисправны.пример
var tasks = new Task[] { await TaskOperationOne(), await TaskOperationTwo() }; Task.WaitAll(tasks); // or await Task.WhenAll(tasks);
если вы хотите запускать задачи в пратикулярном порядке, вы можете получить форму вдохновения этой ответить.