Почему методы Parallel.For/Foreach не работают с асинхронной лямбдой?
Есть следующий кусок кода:
private static void WorkAsync()
{
Parallel.For(0,
20,
async i =>
{
await Task.Delay(50000);
Console.WriteLine(i);
});
}
При вызове метода WorkAsync, он практически сразу возвращает управление вызывающему коду, хотя цикл For ещё не завершился. Я правильно понимаю, что асинхронная лямбда при каждом вызове возвращает управление вызывающему потоку и поэтому не происходит ожидание?
Ответы (1 шт):
Ваша лямбда это async void, а async void невозможно ожидать.
Для асинхронных вызовов можно не использовать Parallel. Тем более у Parallel.For блокирующее синхронное ожидание, что для асинхронной среды не хорошо.
Как-то так это делается:
private static async Task WorkAsync()
{
List<Task> tasks = new();
for (int i = 0; i < 20; i++)
{
tasks.Add(JobAsync(i));
}
await Task.WhenAll(tasks);
}
private static async Task JobAsync(int i)
{
await Task.Delay(50000);
Console.WriteLine(i);
}
Вызов выглядит так:
await WorkAsync();
Если очень хочется, можно через лямбду:
private static async Task WorkAsync()
{
List<Task> tasks = new();
for (int i = 0; i < 20; i++)
{
tasks.Add(((Func<int, Task>)(async index =>
{
await Task.Delay(50000);
Console.WriteLine(index);
}))(i));
}
await Task.WhenAll(tasks);
}
Или так:
private static async Task WorkAsync()
{
List<Task> tasks = new();
Func<int, Task> func = async index =>
{
await Task.Delay(50000);
Console.WriteLine(index);
};
for (int i = 0; i < 20; i++)
{
tasks.Add(func(i));
}
await Task.WhenAll(tasks);
}
Можно даже с ограничением на количество одновременно выполняемых задач: Массовые асинхронные вызовы с ограничением на количество параллельных без семафора