【问题标题】:Difference between writing Asynchronous Code with Task and Asynchronous Code with async await?使用 Task 编写异步代码和使用 async await 编写异步代码之间的区别?
【发布时间】:2019-09-19 12:53:12
【问题描述】:

我有一个关于异步编程的问题:

带有任务的异步代码(没有 async/await)和带有 async/await 的异步代码有什么区别?

在C#中,我们可以使用Task来编写异步代码或方法,也可以使用关键字。


带任务的异步代码(无 Async/Await)

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

带有 Async/Await 的异步代码

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

如果能回答我的问题,我真的很感激。

【问题讨论】:

  • 您应该使用await Task.Delay 而不是Thread.SleepTask.Run。如果您进行了更改,您会发现第二个代码示例将比第一个更短/更简单。
  • 异步方法旨在成为非阻塞操作。当等待的任务正在运行时,异步方法中的等待表达式不会阻塞当前线程。相反,表达式将方法的其余部分注册为延续,并将控制权返回给异步方法的调用者。
  • 第一种方法不是异步的。如果您在控制台应用程序中同时运行这两种方法,您会注意到第一种方法会阻塞 UI,而第二种方法则不会
  • @apomene 这并不完全正确。这一切都取决于调用者对返回的任务做了什么。调用者可以使用Wait 来阻止代码中的任何一个,或者使用await 来阻止任何一个。
  • asyncawait 关键字让您可以通过编写一系列语句来执行异步代码,就像您编写同步代码时一样,即您可以在 @987654331 之后立即调用 Console.WriteLine @ 不使用传递给 ContinueWith 的回调。它使您的异步代码看起来更干净。

标签: c# .net asynchronous async-await task


【解决方案1】:

在C#中,我们可以使用Task来编写异步代码或方法,也可以使用关键字。

这在技术上是正确的,但是在没有async/await 的情况下编写异步代码要正确地完成要困难得多。考虑一下您拥有的代码示例:

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

上面的代码使用具有dangerous default behavior 的低级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 表达,而不是用手动管理的状态对象延续。

在后台,DoWorkAsync 中的 await 最终会调用 ContinueWith。通过让编译器正确生成棘手的代码,您可以避开很多陷阱并最终得到更易于维护的代码。

【讨论】:

  • 谢谢克利里先生 :)
猜你喜欢
  • 2017-07-16
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 2020-07-05
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 1970-01-01
相关资源
最近更新 更多