使用C#,为什么在同步版本可用时等待Async方法?

时间:2018-03-08 08:13:24

标签: c# async-await

有很多关于await和async的解释,现在可以在C#中找到;但似乎没有解释为什么这......

using (XmlReader reader = XmlReader.Create(stream, settings))
{
    while (await reader.ReadAsync())
    {
        // Do something
    }
}

比这更好......

using (XmlReader reader = XmlReader.Create(stream, settings))
{
    while (reader.Read())
    {
        // Do something
    }
}

换句话说,如果您在等待... Async方法做其事情时无意做其他事情,为什么要使用它?如果同步方法可用,为什么不使用它呢?

此Async示例取自:https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlreader?view=netframework-4.7.1

编辑:在阅读了被认为是重复的问题和答案后,他们没有帮助。我特意询问了与被调用的异步方法在同一行上等待的简单情况。我的问题已在下面得到解答。谢谢大家!

4 个答案:

答案 0 :(得分:5)

从根本上说,使用异步方法调用不会阻塞线程,这是任何机器上的有限资源。假设您有一个方法调用,由于网络延迟,繁重的数据库工作负载等,可能需要3秒钟才能完成。如果您同步调用此方法,您的线程实际上就坐在那里等待结果返回,其余部分无视你的申请。

异步方法调用(或async / await,因为它通俗地知道并调用)是非阻塞的。因此,如果你的执行线程遇到一个方法,表明它可以被等待,它将(并且我在这里大大过分简化了)将标志放在沙子中并告诉系统只做那件事并在你'时给我打电话'重做。

现在你可能在想,“但是等等!这是不是意味着另一个线程必须完成当前线程刚委派的工作?!”你是对的。

这就是前景和后台线程的概念所在。前台线程的一个例子就像处理控制器中的Web API调用的线程,或UI渲染线程。

阻塞这些线程有几个原因是有害的,在API线程的情况下,你基本上缩小了在任何给定时间你可以处理的每秒请求数量的窗口。在UI的情况下,当它在后台工作时,它可能会使渲染停止几秒钟。

那么一般的积极和消极是什么?在使用async / await时,你会更均匀地分配线程工作负载,这会损害内存开销(必须记住沙子中所有标志的位置,并跟踪进程何时可以继续)。

当人们说它使应用程序更高效时,通过使其更加并发,但不一定更快,这是真的。

解决Mihir Dave留下的评论:

滥用async / await将包括尝试将其应用于纯计算方法(例如,没有I / O,纯粹是CPU绑定)。那时你增加了很多复杂性和开销,没有任何好处。另一个糟糕的应用程序并不是自上而下,如果你开始尝试“同步”异步方法或“异步”同步方法,死锁的风险会急剧增加。后者在使用过时的API时非常常见,这可能不会暴露异步方法。

关于async / await read的详细阅读将是Q: why-shouldnt-all-functions-be-async-by-default

答案 1 :(得分:2)

它将释放一个线程来执行其他操作(可能),而不是旋转并等待IO完成。对于Web应用程序,这有助于应用程序通过使用这些线程来处理更多请求。对于UI应用程序,它允许主(UI)线程使应用程序响应用户输入。

您可以在.NET here中详细了解async的优点。

答案 2 :(得分:0)

这取决于您的使用案例。使用await将释放当前线程以执行其他操作。如果此线程是桌面应用程序中的UI线程,则必须释放它以处理UI。如果你在网络服务器上,你会想要释放线程来处理其他请求,线程不是空闲的,如果内存占用堆栈空间,它们会占用1MB。

如果您不关心任何调用同步版本的情况,那么

答案 3 :(得分:0)

你写道:

  

如果您在等待期间无意做其他事情......

好吧,也许你的程序在等待期间无意做其他事情,但你的来电者可能想要!

如果你调用等待某个任务,并且任务还没有完成,你的线程就会上调调用堆栈以查看你的调用者是否正在等待你的任务,如果没有,则线程开始执行语句,直到他必须等待。线程再次上调调用堆栈。

所以即使你不必做一些有用的事情,如果你认为你的调用者可能有一点点机会想要做某事而不是等到你准备好了,那么每当你更好地让你的函数异步让coice调用异步函数。如果您认为您的类将被广泛使用,请考虑创建异步和非异步版本