Разница между написанием асинхронного кода с помощью задачи и асинхронного кода с помощью асинхронного ожидания? - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть вопрос об асинхронном программировании:

В чем разница между асинхронным кодом с задачей (без асинхронного / ожидающего) и асинхронным кодом с асинхронным / ожидающим?

В C # мы можемиспользуйте Task для написания асинхронного кода или метода, а также мы можем использовать ключевые слова.


асинхронный код с заданием (без асинхронного / ожидающего)

static Task DoWorkAsync()
{
    var work = Task.Run(() => { Thread.Sleep(5000); });
    var workcompleted = work.ContinueWith((x) => { Console.WriteLine("Work Completed!!!"); });
    return work;
}

асинхронный код с асинхронным/ Ожидание

    static async Task DoWorkAsync()
    {
        await Task.Run(() => { Thread.Sleep(10000); });
        Console.WriteLine("Work Completed");
    }

Я очень признателен, если ответите на мой вопрос.

1 Ответ

3 голосов
/ 19 сентября 2019

В 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.Позволяя компилятору правильно сгенерировать хитрый код, вы обойдете множество ловушек и получите более понятный код.

...