Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.
Для связи: @SBenzenko
Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Post #1223
1.52K
День девятьсот девяносто восьмой. #ЗаметкиНаПолях #AsyncTips
Обработка задач при завершении
Задача
Имеется коллекция задач, которые будут использоваться с await; требуется организовать обработку каждой задачи после ее завершения. При этом обработка каждой задачи должна происходить сразу же после завершения, без ожидания других задач.
Допустим, у нас есть некоторый набор однотипных задач. Для простоты возьмём задачу, которая просто ожидает заданное количество секунд:
Решение заключается в добавлении оборачивающего асинхронного метода, который обеспечивает ожидание задачи и обработку ее результата. Этот метод можно записать как асинхронную лямбду:
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
Обработка задач при завершении
Задача
Имеется коллекция задач, которые будут использоваться с await; требуется организовать обработку каждой задачи после ее завершения. При этом обработка каждой задачи должна происходить сразу же после завершения, без ожидания других задач.
Допустим, у нас есть некоторый набор однотипных задач. Для простоты возьмём задачу, которая просто ожидает заданное количество секунд:
async Task<int> DelayAndReturnAsync(int value)Создадим коллекцию этих задач:
{
await Task.Delay(TimeSpan.FromSeconds(value));
return value;
}
Task<int> taskA = DelayAndReturnAsync(2);Можно ожидать каждую задачу в цикле, но тогда они будут обрабатываться последовательно в порядке их нахождения в коллекции:
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
Task<int>[] tasks = new[] { taskA, taskB, taskC };
// Выводит "2", "3" и "1" вместо "1", "2" и "3".Решение
async Task ProcessTasksAsync(Task<int>[] tasks)
{
foreach (Task<int> task in tasks)
{
var result = await task;
Trace.WriteLine(result);
}
}
Решение заключается в добавлении оборачивающего асинхронного метода, который обеспечивает ожидание задачи и обработку ее результата. Этот метод можно записать как асинхронную лямбду:
async Task ProcessTasksAsync(Task<int>[] tasks)В этом решении обработка задач выполняется конкурентно, тогда как в исходном коде задачи обрабатывались по очереди. Обычно это не создаёт затруднений, но, если такой способ обработки в вашей ситуации недопустим, рассмотрите возможность использования блокировок.
{
Task[] processing = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
}).ToArray();
// Ожидаем завершения всей обработки
await Task.WhenAll(processing);
}
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
