是的,你忽略了async并不与速度有关,只与请求每秒的概念略微相关的事实。
Async只做一件事情。如果正在等待任务,并且该任务不涉及CPU绑定工作,并且因此线程变为空闲状态,则该线程可能被释放以返回到池中执行其他工作。
就是这样,Async简而言之。Async的目的是更有效地利用资源。在您可能拥有线程被卡住,只是坐在那里等待某些I / O操作完成的情况下,它们可以被分配到其他工作。这导致您应内部化的两个非常重要的想法:
1. Async!= 更快。事实上,Async更慢。异步操作涉及开销:上下文切换,在堆上进行数据的移动等。这会增加额外的处理时间。即使在某些情况下仅谈论微秒,Async始终比等效的同步过程慢。周期。全站点。
2. 仅在服务器负载时Async才会为您节省资源。只有当服务器处于压力状态时,Async才会给它一些急需的喘息时间,而同步可能会让它跪下。这一切都关乎规模。如果您的服务器只处理微不足道的请求数量,您很可能永远不会看到与同步相比的差异,而且正如我所说,您可能会由于涉及的开销而使用更多资源,具有讽刺意味。
这并不意味着您不应该使用Async。即使您的应用程序今天不流行,也不意味着它以后不会流行,那时重新调整所有代码以支持Async将是一场噩梦。 Async的性能成本通常可以忽略不计,如果您最终需要它,它将是救星。
更新
关于保持Async的性能成本可以忽略不计,有一些有用的提示,在大多数关于C#中的Async的讨论中不太明显或没有很好地解释。
尽可能经常使用ConfigureAwait(false)。
await DoSomethingAsync().ConfigureAwait(false);
几乎每个异步方法调用都应该跟随这个操作,但除了少数特例。
ConfigureAwait(false)
告诉运行时,在异步操作期间不需要保留同步上下文。默认情况下,当您等待异步操作时,会创建一个对象来在线程切换之间保留线程本地数据。这占用了处理异步操作所需的大部分处理时间,并且在许多情况下完全没有必要。它真正重要的地方只是像 action 方法,UI 线程等地方——那些与线程关联的信息需要被保留的地方。您只需要保留此上下文一次,因此只要例如您的 action 方法使用保持同步上下文完整性的异步操作等待,那么该操作本身可以执行其他未保留同步上下文的异步操作。因此,在像 action 方法这样的地方将对
await
的使用限制到最少,并尝试将多个异步操作分组到一个可以调用该 action 方法的单个异步方法中。这将减少使用异步时的开销。值得注意的是,这仅适用于 ASP.NET MVC 中的操作。ASP.NET Core 使用依赖注入模型而不是静态模型,因此不需要担心线程本地变量。在其他情况下,您可以在 ASP.NET Core 操作中使用
ConfigureAwait(false)
,但在 ASP.NET MVC 中则不能。事实上,如果尝试在 ASP.NET MVC 中使用,则会导致运行时错误。
尽可能减少需要保留的本地变量数量。在调用 await 之前初始化的变量会添加到堆中,并在任务完成后弹出。您声明的越多,就会有更多放置在堆上的内容。特别是,大型对象图表可以对此造成破坏,因为这是要移动的大量信息。有时这是不可避免的,但应该注意这一点。
尽可能省略async
/await
关键字。例如,请考虑以下内容:
public async Task DoSomethingAsync()
{
await DoSomethingElseAsync();
}
在这里,DoSomethingElseAsync
返回一个被等待并解除包装的Task
。然后,创建了一个新的Task
来从DoSometingAsync
返回。但是,如果您将方法编写为:
public Task DoSomethingAsync()
{
return DoSomethingElseAsync();
}
DoSomethingAsync
直接返回由 DoSomethingElseAsync
返回的 Task
。这样可以减少大量开销。