Запуск нескольких задач async и ожидание их завершения

Мне нужно запустить несколько асинхронных задач в консольном приложении и дождаться их завершения до дальнейшей обработки.

Там много статей, но я, кажется, больше смущен, чем больше читаю. Я читал и понимал основные принципы библиотеки задач, но я явно пропускаю ссылку где-то.

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

Какая самая простая реализация для такого сценария?

Ответ 1

В обоих ответах не упоминается ожидаемая 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 до того, как будет возвращена вызывающему.

Ответ 2

Вы можете создать множество задач, таких как:

List<Task> TaskList = new List<Task>();
foreach(...)
{
   var LastTask = new Task(SomeFunction);
   LastTask.Start();
   TaskList.Add(LastTask);
}

Task.WaitAll(TaskList.ToArray());

Ответ 3

Лучшим вариантом, который я видел, является следующий метод расширения:

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();
});

Ответ 4

Вы хотите связать цепочку Task s или их можно вызвать параллельно?

Для цепочки
Просто сделайте что-нибудь вроде

Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);

и не забудьте проверить предыдущий экземпляр Task в каждом ContinueWith, поскольку он может быть поврежден.

Параллельно
Самый простой метод, с которым я столкнулся: Parallel.Invoke В противном случае Task.WaitAll или вы даже можете использовать WaitHandle для выполнения обратного отсчета до нулевых действий слева (подождите, есть новый класс: CountdownEvent) или...

Ответ 5

Вы можете использовать WhenAll который вернет ожидаемую Task или WaitAll которой нет типа возврата, и блокирует дальнейшее выполнение кода, Thread.Sleep с Thread.Sleep пока все задачи не будут завершены, отменены или не будут устранены.

enter image description here

пример

var tasks = new Task[] {
    await TaskOperationOne(),
    await TaskOperationTwo()
};

Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);

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

Ответ 6

Вот как я делаю это с массивом Func < > :

var tasks = new Func<Task>[]
{
   () => myAsyncWork1(),
   () => myAsyncWork2(),
   () => myAsyncWork3()
};

await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async    
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync