Task.WhenAll(SomeList.Select(x=>AsyncMethod(x))) будет ли параллельная работа?
Допустим, есть коллекция значений и какой-то асинхронный метод.
Если я сделаю вот так:
Task.WhenAll(SomeList.Select(x=>AsyncMethod(x)))
То будет ли организована какая-нибудь параллельная работа автоматически или все это целиком зависит от того, как устроен асинхронный метод сам по себе или все таки в каких-то случаях параллельная работа будет?
Ответы (3 шт):
Нет, конечно.
Async/await вовсе ничего не знает о потоках, Task — всего лишь абстракция задания, которое каким-то образом выполняется.
Если ваши Task'и ожидают внутренние подзадания через await (и внутренние подзадания тоже all the way down), и не содержат медленного кода (например, длинных синхронных вычислений), обычно неважно, в каком потоке они выполняются, т. к. реальная работа разных заданий не будет блокировать друг друга.
Если же у вас есть синхронный тяжёлый код, нужно явно «увести» его из потока (например, при помощи Task.Run) внутри AsyncMethod. (Если AsyncMethod так не делает из каких-то соображений, напишите вместо него лямбду-обёртку.)
Вариант 1 - отсутствие чего либо асинхронного
async Task Main()
{
var tasks = Enumerable.Range(0, 10).Select(x=>AsyncMethod()).ToList();
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(tasks);
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
}
async Task AsyncMethod()
{
Console.WriteLine($"started in thread {Thread.CurrentThread.ManagedThreadId}");
var ret = await Task.FromResult(10);
Console.WriteLine($"finished in thread {Thread.CurrentThread.ManagedThreadId}");
}
В выводе все потоки одинаковые
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
started in thread 12
finished in thread 12
main in thread 12
main in thread 12
Вариант 2 - какая то асинхронная задача
async Task Main()
{
var tasks = Enumerable.Range(0, 10).Select(x=>AsyncMethod()).ToList();
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(tasks);
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
}
async Task AsyncMethod()
{
Console.WriteLine($"started in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000);
Console.WriteLine($"finished in thread {Thread.CurrentThread.ManagedThreadId}");
}
В выводе выполнение прыгает по потокам, можно думать о какой то многопоточности
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
main in thread 12
finished in thread 14
finished in thread 8
finished in thread 11
finished in thread 11
finished in thread 11
finished in thread 11
finished in thread 8
finished in thread 9
finished in thread 14
finished in thread 10
main in thread 10
Вариант 3 - какая то асинхронная задача + контекст синхронизации WPF
async Task Main()
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
var tasks = Enumerable.Range(0, 10).Select(x=>AsyncMethod()).ToList();
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(tasks);
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
}
async Task AsyncMethod()
{
Console.WriteLine($"started in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000);
Console.WriteLine($"finished in thread {Thread.CurrentThread.ManagedThreadId}");
}
И мы снова в одном потоке
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
main in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
finished in thread 12
main in thread 12
Вариант 3 - какая то асинхронная задача + контекст синхронизации WPF + ConfigureAwait(false)
async Task Main()
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
var tasks = Enumerable.Range(0, 10).Select(x=>AsyncMethod()).ToList();
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(tasks);
Console.WriteLine($"main in thread {Thread.CurrentThread.ManagedThreadId}");
}
async Task AsyncMethod()
{
Console.WriteLine($"started in thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine($"finished in thread {Thread.CurrentThread.ManagedThreadId}");
}
И снова несколько потоков
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
started in thread 12
main in thread 12
finished in thread 6
finished in thread 18
finished in thread 6
finished in thread 6
finished in thread 6
finished in thread 6
finished in thread 6
finished in thread 6
finished in thread 14
finished in thread 18
main in thread 12
Таким образом, наличие асинхронного метода не говорит ничего о том, будет ли асинхронный вызов вообще и будет ли использована многопоточность.
Добавлю ещё немного слов к ответам выше. Даже если мы будем говорить о многопоточности -это метод, который выделяет отдельные потоки выполнения; они по существу являются легкими процессами с некоторыми преимуществами по отношению к общим ресурсам от их родителя. А параллелизм - способ выполнения процессов/потоков. Они либо последовательны (следуют друг за другом), либо параллельны (происходят одновременно).
Даже имея многопоточность вы ничего не можете говорить о параллельности.