В C # мы можем использовать Task для написания асинхронного кода или метода, а также мы можем использовать ключевые слова.
Это технически true, но при написании асинхронного кодабез async
/ await
гораздо сложнее сделать правильно.Рассмотрим пример кода, который у вас есть:
static Task DoWorkAsync()
{
var work = Task.Run(() => { Thread.Sleep(5000); });
var workcompleted = work.ContinueWith((x) => { Console.WriteLine("Work Completed!!!"); });
return work;
}
Приведенный выше код использует низкоуровневый метод ContinueWith
, который имеет опасное поведение по умолчанию .В частности, он будет неявно захватывать текущий TaskScheduler
.
. Приведенный выше код возвращает Task
, который завершается после завершения делегата Task.Run
.Делегат ContinueWith
имеет , а не , запущенный, когда эта задача завершена, и, поскольку workcompleted
игнорируется, любые исключения из делегата ContinueWith
отбрасываются.Вызывающий код не может знать, когда завершен делегат ContinueWith
или успешно ли он завершен.
Сравните с кодом async
/ await
, который короче, понятнее, проще в обслуживании и более корректен:
static async Task DoWorkAsync()
{
await Task.Run(() => { Thread.Sleep(10000); });
Console.WriteLine("Work Completed");
}
Приведенный выше код возвращает Task
, который завершается после завершения всего DoWorkAsync
(включая WriteLine
).Любые исключения фиксируются и помещаются в задачу.
Кроме того, более сложная логика, такая как циклы и повторы, гораздо более естественно выражается с помощью async
/ await
, а не продолжения с объектами состояния, управляемыми вручную.
Под капотом await
in DoWorkAsync
в итоге вызовет ContinueWith
.Позволяя компилятору правильно сгенерировать хитрый код, вы обойдете множество ловушек и получите более понятный код.