我想澄清一下使用Await和Async的额外好处是什么。
如果我的应用程序正在调用等待Func1()
(这里没有阻止UI)。并且Func1
正在等待Func2()
,但Func2()
的结果对Func1
完成工作很重要,那么我为什么需要Func2()
1}}等待。 Func1()
执行会花费同样长的时间,因为它等待Func2
完成。 await所做的就是添加StateMachine开销。
我在这里遗漏了什么吗?
答案 0 :(得分:29)
更好的标语 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
}
答案 1 :(得分:8)
主要的好处是等待异步方法将工作线程返回到池中以用于其他调用(例如,对.NET MVC Web应用程序的Web请求)。异步工作在IO完成线程上完成。当等待的方法完成时,另一个工作线程将收集结果并继续执行。这可以防止工作线程池耗尽,并允许您的应用程序处理更多负载(CPU,内存和网络吞吐量取决于)。
至于“等待一路走下去”,这对我来说似乎是一个问题。通常,await
与应用程序必须等待的外部资源(数据库调用,HTTP请求等)相关联。如果等待没有外部IO依赖关系的代码,则会产生不需要的开销。在awaits
方法链中可能有多个async
,但是等待一些自己调用await
但没有其他外部IO依赖的代码并不好,只会添加回调/编译器开销
答案 2 :(得分:3)
通常,async
/ await
背后的推理反过来说:
无论出于何种原因,您决定使用Func2
更容易编写await
。因此,您可以通过添加所需的await
来简化方法,这意味着您还必须更改方法签名(现在它将包含async
关键字以及返回类型Task
或{{ 1}})。
由于返回类型已更改,因此您无法像以前那样调用Task<T>
(Func2
),因此您现在需要更改调用方法var result = Func2();
。调整Func1
的最简单方法通常是Func1
,async
。
然后,出于同样的原因(更改了签名),您需要更改对await Func2()
的所有调用,依此类推,直到找到某种入口点(UI事件处理程序或您的{ {1}}方法,或其他东西)。
所以你不要开始制作“最外层”方法Func1
并继续使用“内部”(被称为)方法;你通常在向相反的方向做事Main
(从“最里面的”方法回到调用的方法)。 This other answer将此想法称为“async as up up up”。
答案 3 :(得分:2)
&#34;这种异步方法缺乏等待&#39;操作员将同步运行&#34;如果你不等待异步方法会发生什么。要利用异步方法的好处,你必须等待它,将调用者变成一个可以等待的异步方法等。
从流程图中可以看到异步方法返回一个Task(将来要完成工作的承诺),并对其调用者产生控制权。然后,调用者可以继续工作而不依赖于此结果。显然,这需要在调用堆栈中冒泡以找到所有这些可以在没有结果的情况下完成的有益工作(在UI应用程序中,这项工作将包括取消阻止UI,这就是为什么它一直是异步的原因以下示例中的事件处理程序。)
从我最初的误读。所以你发现了一些你需要调用的异步代码,是否值得异步等待模式传播你的代码:
我已经听到很多关于async-await的主要问题是它实际上做得太简单了。 Program flow变得复杂了。我非常喜欢async-await,但遗憾的是在大多数异步代码中我都看到它不值得,而且不必要地破坏了我的调用堆栈。
要记住的一件好事是50ms rule。
&#34;这是Microsoft遵循WinRT API的规则;任何花费少于50毫秒的东西都被认为是“快速”并且足够接近“立即”,因为它们不需要异步API。&#34;
这是在鼓励异步等待的背景下使用的。但是,我认为应该同样适用于告诉开发人员使用async-await来实现基本上即时的功能。
答案 4 :(得分:0)
在基于UI的应用程序中,async await提供了一种非常简洁的方式来处理导致UI更新的异步调用。如果是顶级&#39;来自UI的处理程序正在等待结果,然后在整个链中执行相同的操作可能没有真正的好处,除非这样做是有道理的。异步等待的设计目标是使异步编程看起来更加同步和连续,并且没有散布的回调等 - 使异步编码更具可评估性。这不是你需要随意使用的东西。