Запуск нескольких задач async и ожидание их завершения
Мне нужно запустить несколько задач async в консольном приложении и дождаться их завершения до дальнейшей обработки.
Там много статей, но я, кажется, больше смущен, чем больше читаю. Я читал и понимал основные принципы библиотеки задач, но я явно пропускаю ссылку где-то.
Я понимаю, что можно объединить задачи так, чтобы они запускались после того, как они завершались (что в значительной степени является сценарием для всех прочитанных статей), но я хочу, чтобы все мои задачи выполнялись одновременно, и я хочу знать один раз они все закончены.
- Лучший способ конвертировать метод async на основе обратного вызова в ожидаемую задачу
- Выполнение задачи в фоновом режиме в приложении WPF
- Отмена ожидающей задачи синхронно в streamе пользовательского интерфейса
- Когда использовать Task.Delay, когда использовать Thread.Sleep?
- Шаблон для самоотдачи и перезапуска задачи
Какова самая простая реализация для такого сценария?
- Как ограничить количество одновременных операций асинхронного ввода-вывода?
- Почему это асинхронное действие зависает?
- Каков правильный способ отмены асинхронной операции, которая не принимает CancellationToken?
- Использовать Task.Run () в синхронном методе, чтобы избежать тупиковой остановки в асинхронном методе?
- ConfigureAwait подталкивает продолжение в stream пула
- Секвенирование и реорганизация задач
- Запуск двух асинхронных задач параллельно и сбор результатов в .NET 4.5
- Разница между TPL и async / await (Обработка streamов)
В обоих ответах не упоминается ожидаемая Task.WhenAll
После Task.WhenAll
:
var task1 = DoWorkAsync(); var task2 = DoMoreWorkAsync(); await Task.WhenAll(task1, task2);
Основное различие между Task.WaitAll
и Task.WhenAll
заключается в том, что первый будет блокировать (подобно использованию Wait
в одной задаче), в то время как последний не будет и может быть ожидаем, возвращая управление вызывающему абоненту до тех пор, пока все задачи не закончатся.
Более того, обработка исключений отличается:
Task.WaitAll
:
По крайней мере один из экземпляров Task был отменен – или – исключение было отправлено во время выполнения хотя бы одного из экземпляров Task. Если задача была отменена, в своде InnerExceptions в агрегированном исключении содержится исключение OperationCanceledException.
Task.WhenAll
:
Если какая-либо из поставленных задач завершена в неисправном состоянии, возвращенная задача также будет завершена в состоянии Faulted, где ее исключения будут содержать агрегацию набора исключенных исключений из каждой из поставленных задач.
Если ни одна из поставленных задач не сработала, но хотя бы одна из них была отменена, возвращаемая задача завершится в состоянии «Отменено».
Если ни одна из задач не была выполнена, и ни одна из задач не была отменена, итоговая задача завершится в состоянии RanToCompletion. Если предоставленный массив / перечисляемый не содержит задач, возвращаемая задача немедленно перейдет в состояние RanToCompletion до того, как будет возвращена вызывающему.
Вы могли бы создать много задач, таких как:
List TaskList = new List (); foreach(...) { var LastTask = new Task(SomeFunction); LastTask.Start(); TaskList.Add(LastTask); } Task.WaitAll(TaskList.ToArray());
Лучший вариант, который я видел, – это следующий метод расширения:
public static Task ForEachAsync(this IEnumerable sequence, Func 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 для обратного отсчета до нулевых действий слева (подождите, есть новый class: CountdownEvent
) или …
Вы можете использовать WhenAll
который вернет ожидаемую Task
или WaitAll
которой нет типа возврата, и блокирует дальнейшее выполнение кода, Thread.Sleep
с Thread.Sleep
пока все задачи не будут завершены, отменены или не будут устранены.
пример
var tasks = new Task[] { await TaskOperationOne(), await TaskOperationTwo() }; Task.WaitAll(tasks); // or await Task.WhenAll(tasks);
Если вы хотите запускать задачи в порядке приоритета, вы можете получить вдохновение от этого андерсера.
Вот как я делаю это с помощью массива Func <> :
var tasks = new Func[] { () => myAsyncWork1(), () => myAsyncWork2(), () => myAsyncWork3() }; await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync