Асинхронные методы, возвращающие void и поддерживающие await
Если асинхронный метод должен поддерживать
await
, тогда используйте необобщенный класс
Task
и опустите любые операторы
return
, например:
static async Task MethodReturningTaskOfVoidAsync()
{
await Task.Run(() => { /* Выполнить какую-то работу... */
Thread.Sleep(4_000);
});
Console.WriteLine("Void method completed");
// Метод завершен
}
Затем в коде, вызывающем этот метод, примените ключевое слово
await
:
MethodReturningVoidAsync();
Console.WriteLine("Void method complete");
Асинхронные методы, возвращающие void и работающие в стиле "запустил и забыл"
Если метод должен быть асинхронным, но не обязан поддерживать
await
и применяться в сценариях "запустил и забыл", тогда добавьте ключевое слово
async
и сделайте возвращаемым типом
void
, а не
Task
. Методы такого рода обычно используются для задач вроде ведения журнала, когда нежелательно, чтобы запись в журнал приводила к задержке выполнения остального кода.
static async void MethodReturningVoidAsync()
{
await Task.Run(() => { /* Выполнить какую-то работу... */
Thread.Sleep(4_000);
});
Console.WriteLine("Fire and forget void method completed");
// Метод завершен
}
Затем в коде, вызывающем этот метод, ключевое слово
await
не используется:
MethodReturningVoidAsync();
Console.WriteLine("Void method complete");
Асинхронные методы с множеством контекстов await
Внутри реализации асинхронного метода разрешено иметь множество контекстов
await
. Следующий код является вполне допустимым:
static async Task MultipleAwaits()
{
await Task.Run(() => { Thread.Sleep(2_000); });
Console.WriteLine("Done with first task!");
// Первая задача завершена!
await Task.Run(() => { Thread.Sleep(2_000); });
Console.WriteLine("Done with second task!");
// Вторая задача завершена!
await Task.Run(() => { Thread.Sleep(2_000); });
Console.WriteLine("Done with third task!");
// Третья задача завершена!
}
Здесь каждая задача всего лишь приостанавливает текущий поток на некоторый период времени; тем не менее, посредством таких задач может быть представлена любая единица работы (обращение к веб-службе, чтение базы данных или что-нибудь еще). Еще один вариант предусматривает ожидание не каждой отдельной задачи, а всех их вместе. Это более вероятный сценарий, когда имеются три работы (скажем, проверка поступления сообщений электронной почты, обновление сервера, загрузка файлов), которые должны делаться в пакете, но могут выполняться параллельно. Ниже приведен модифицированный код, в котором используется метод
Task.WhenAll()
:
static async Task MultipleAwaits()
{
var task1 = Task.Run(() =>
{
Thread.Sleep(2_000);
Console.WriteLine("Done with first task!");
});
var task2=Task.Run(() =>
{
Thread.Sleep(1_000);
Console.WriteLine("Done with second task!");
});
var task3 = Task.Run(() =>
{
Thread.Sleep(1_000);
Console.WriteLine("Done with third task!");
});
await Task.WhenAll(task1, task2, task3);
}
Запустив программу, вы увидите, что три задачи запускаются в порядке от наименьшего значения, указанного при вызове метода
Sleep()
:
Fun With Async ===>
Done with work!
Void method completed
Done with second task!
Done with third task!
Done with first task!
Completed
Существует также метод
WhenAnу()
, возвращающий задачу, которая завершилась. Для демонстрации работы
WhenAny()
измените последнюю строку метода
MultipleAwaits()
следующим образом: