В чем выгода асинхронности, если не во времени исполнения?
Не могу понять, в чем профит асинхронности в .net (не ui приложения).
Console.WriteLine("Start Main");
await PrintAsync();
Console.WriteLine("End Main");
void Print()
{
Thread.Sleep(3000);
Console.WriteLine("Print");
}
async Task PrintAsync()
{
Console.WriteLine("Start PrintAsync");
await Task.Run(() => Print());
Console.WriteLine("End PrintAsync");
}
Я бы понял, если бы вывод был таким:
Start Main
Start PrintAsync
End Main
Print
End PrintAsync
Т.е. профит такой: main работает, дошел до долгой задачи, отдал ее другому потоку, а сам продолжил работать, после чего подхватил ответ от той долгой задачи. Поток не останавливает свою работу. Но вывод, конечно, другой:
Start Main
Start PrintAsync
Print
End PrintAsync
End Main
Т.е. поток main все равно останавливается и ждет, пока придет ответ от асинхронной операции, отданной на сторону. Не проще ли тогда забить на асинхронность и делать все синхронно, раз все равно придется ждать?!
Ответы (2 шт):
Полностью асинхронный код:
Console.WriteLine("Start Main");
// Запускаем задачу PrintAsync и спокойно идём дальше
var printTask = PrintAsync();
Console.WriteLine("End Main");
// Ждём завершения задачи PrintAsync
await printTask;
async Task PrintDelayAsync()
{
// Ждём 3 секунды, но при этом поток не будет занят
await Task.Delay(3000);
Console.WriteLine("Print");
}
async Task PrintAsync()
{
Console.WriteLine("Start PrintAsync");
// Ждём пока метод отработает, но поток не занят
await PrintDelayAsync();
Console.WriteLine("End PrintAsync");
}
Весь этот код может выполняться даже одним потоком, при этом в моменты ожидания await
этот поток освобождается может выполнять какие-то другие асинхронные задачи из вашего кода, если они у вас будут.
Пример параллельного исполнения задач:
Console.WriteLine("Start Main");
await PrintAsync();
Console.WriteLine("End Main");
async Task Print1Async()
{
await Task.Delay(3000);
Console.WriteLine("Print 1");
}
async Task Print2Async()
{
await Task.Delay(2000);
Console.WriteLine("Print 2");
}
async Task Print3Async()
{
await Task.Delay(1000);
Console.WriteLine("Print 3");
}
async Task PrintAsync()
{
Console.WriteLine("Start PrintAsync");
var tasks = new List<Task>() { Print1Async(), Print2Async(), Print3Async() };
await Task.WhenAll(tasks);
Console.WriteLine("End PrintAsync");
}
Вывод:
Start Main
Start PrintAsync
Print 3
Print 2
Print 1
End PrintAsync
End Main
То есть суть в чём - запустились сразу 3 задачи, выполнились они не в том порядке, как были запущены, а где меньше задержка, та раньше и выполнилась. При этом, повторюсь, достаточно одного потока, чтобы выполнять этот код. Что очень существенно, когда речь идёт о сильно загруженных программах типа веб-сервера или какого-то обработчика данных реального времени.
Асинхронность позволяет вынести отдельные задачи из основного потока в специальные асинхронные методы, и при этом более экономно использовать потоки.
Асинхронные методы выполняются в отдельных потоках. Однако при выполнении продолжительной операции поток асинхронного метода возвратится в пул потоков, и будет использоваться для других задач.
А когда продолжительная операция завершит свое выполнение, для асинхронного метода опять выделяется поток из пула потоков, и асинхронный метод продолжает свою работу.