为什么一直使用Async / await

我想澄清一下使用Await和Async的额外好处是什么。

如果我的应用程序正在调用await Func1() (这里没有阻止UI)。 并且Func1正在调用等待Func2() ,但是Func2()的结果对于Func1完成它的工作很重要,那么为什么我需要使Func2()等待。 Func1()执行将花费同样长的时间,因为它正在等待Func2完成。 await所做的就是添加StateMachine开销。

我在这里错过了什么吗?

一个更好的口号async一直向上 。 因为您从异步操作开始并使其调用者异步,然后是下一个调用者等。

当你有一个固有的异步操作(通常是I / O但不一定)时你应该使用async-await ,并且你不想浪费一个空闲的线程等待操作完成。 选择async操作而不是同步操作不会加快操作速度。 它将花费相同的时间(甚至更多)。 它只是使该线程继续执行一些其他CPU绑定工作而不是浪费资源。

但是为了能够await该操作,该方法需要是async ,并且调用者需要await它等等。

因此, async一直使您能够实际进行异步调用并释放任何线程。 如果它一直没有async ,那么一些线程被阻塞。

所以这:

 async Task FooAsync() { await Func1(); // do other stuff } async Task Func1() { await Func2(); // do other stuff } async Task Func2() { await tcpClient.SendAsync(); // do other stuff } 

比这更好:

 void Foo() { Func1(); // do other stuff } void Func1() { Func2().Wait(); // Synchronously blocking a thread. // do other stuff } async Task Func2() { await tcpClient.SendAsync(); // do other stuff } 

主要的好处是等待异步方法将工作线程返回到池中以用于其他调用(例如,对.NET MVC Web应用程序的Web请求)。 异步工作在IO完成线程上完成。 当等待的方法完成时,另一个工作线程将收集结果并继续执行。 这可以防止工作线程池耗尽,并允许您的应用程序处理更多负载(CPU,内存和网络吞吐量取决于)。

至于“等待一路下来”,这对我来说似乎是一个问题。 通常, await与应用程序必须等待的外部资源(数据库调用,HTTP请求等)相关联。 如果等待没有外部IO依赖性的代码,则会产生不需要的开销。 在async方法链中可能有多个awaits ,但等待一些本身调用await但没有其他外部IO依赖的代码并不好,只会添加回调/编译器开销。

通常, async / await背后的推理async说:

无论出于何种原因,您决定使用await更容易编写Func2 。 因此,通过添加所需的await简化方法,这意味着您还必须更改方法签名(现在它将包含async关键字和TaskTask的返回类型)。

因为返回类型已更改,所以您不能再像以前那样调用Func2var result = Func2(); ),因此您现在需要更改调用方法Func1 。 调整Func1的最简单方法通常是使其async ,并await Func2()

然后,出于同样的原因(更改签名),您将需要更改对Func1所有调用,依此类推,直到您获得某种入口点(UI事件处理程序或Main方法或其他内容)。

所以你不要开始使“最外层”方法async并继续使用“内部”(被称为)方法; 你async会在向相反的方向进行async (从“最里面的”方法回到调用的方法)。 另一个答案称这个想法“一直异步”

“如果你没有等待异步方法,那么这种异步方法缺少’await’运算符并将同步运行”。 要利用异步方法的好处,您必须等待它,将调用者转换为可以等待的异步方法等。

从流程图中可以看出,异步方法返回一个Task(将来要完成工作的承诺)并将控制权交给它的调用者。 然后,调用者可以继续工作,而不依赖于此结果。 显然,这需要冒泡调用堆栈以找到所有这些可以在没有结果的情况下完成的有益工作(在UI应用程序中,这项工作将包括解锁UI,这就是为什么它一直异步到事件处理程序的原因在下面的例子中)。


从我最初的误读。 所以你发现了一些你需要调用的异步代码,是否值得异步等待模式传播你的代码:

我已经听到很多关于async-await的主要问题是它实际上是一个非常简单的语法。 程序流程变得复杂。 我真的很喜欢async-await,但不幸的是在大多数异步代码中,我看到它不值得,只是不必要地破坏了我的调用堆栈。

要记住的一件好事是50ms规则 。

“这是微软遵循WinRT API的规则;任何花费少于50毫秒的东西都被认为是”快速“,并且足够接近”立即“,他们不需要异步API。”

这是在鼓励异步等待的背景下使用的。 但是,我认为应该同样适用于告诉开发人员使用async-await来实现基本上即时的function。


https://msdn.microsoft.com/en-us/cc300389.aspx#E

在基于UI的应用程序中,async await提供了一种非常简洁的方式来处理导致UI更新的异步调用。 如果来自UI的“顶级”处理程序正在等待结果,则除非有意义,否则在整个链中执行相同操作可能没有任何实际好处。 异步等待的设计目标是使异步编程看起来更加同步和连续,并且没有散布的回调等 – 使异步编码更具可评估性。 这不是你需要随意使用的东西。