我在 Controller 中写了几个 Action 方法来测试 之间的区别同步 和 异步 ASP.NET 核心中的 Controller 操作:
[Route("api/syncvasync")]
public class SyncVAsyncController : Controller
{
[HttpGet("sync")]
public IActionResult SyncGet()
{
Task.Delay(200).Wait();
return Ok(new { });
}
[HttpGet("async")]
public async Task<IActionResult> AsyncGet()
{
await Task.Delay(200);
return Ok(new { });
}
}
然后我对同步端点进行负载测试:
...后跟异步端点:
如果我将延迟增加到 1000 毫秒,结果如下
如您所见, 没有太大区别。每秒请求数 - 我希望异步端点每秒处理更多请求。我错过了什么吗?
最佳答案
是的,您忽略了异步与速度无关的事实,它与每秒请求数的概念仅略有相关。
异步只做一件事。如果正在等待一个任务,并且该任务不涉及 CPU 密集型工作,因此该线程变为空闲状态,则该线程可能会被释放以返回到池中以执行其他工作。
就是这样。简而言之,异步。异步的目的是更有效地利用资源。在您可能有线程被捆绑的情况下,只是坐在那里轻敲他们的脚趾,等待某些 I/O 操作完成,他们可以转而处理其他工作。这导致您应该内化两个非常重要的想法:
这并不意味着您不应该使用异步。即使您的应用程序今天不流行,也不意味着它不会在以后流行,并且在那时重新调整所有代码以支持异步将是一场噩梦。异步的性能成本通常可以忽略不计,如果您最终需要它,它将成为救命稻草。
更新
关于保持异步的性能成本可以忽略不计,有一些有用的技巧,在 C# 中的异步的大多数讨论中,这些技巧并不明显或没有很好地说明。
ConfigureAwait(false)
尽可能多。await DoSomethingAsync().ConfigureAwait(false);
除了一些特定的异常(exception),几乎每个异步方法调用都应该跟在 this 之后。
ConfigureAwait(false)
告诉运行时您不需要在异步操作期间保留的同步上下文。默认情况下,当您等待异步操作时,会创建一个对象以保留线程切换之间的线程局部变量。这占用了处理异步操作所涉及的大部分处理时间,并且在许多情况下完全没有必要。唯一真正重要的地方是操作方法、UI 线程等 - 需要保留与线程相关的信息的地方。您只需要保留此上下文一次,例如,只要您的操作方法等待同步上下文完整的异步操作,该操作本身就可以执行其他不保留同步上下文的异步操作。因此,您应该限制 await
的使用。尽量减少操作方法之类的内容,而是尝试将多个异步操作分组到该操作方法可以调用的单个异步方法中。这将减少使用异步所涉及的开销。值得注意的是,这只是对 ASP.NET MVC 中的操作的关注。 ASP.NET Core 使用依赖注入(inject)模型而不是静态模型,因此不需要关注线程局部变量。在其他情况下,您可以使用 ConfigureAwait(false)
在 ASP.NET Core 操作中,但不在 ASP.NET MVC 中。事实上,如果你尝试,你会得到一个运行时错误。 async
/await
关键词。例如,考虑以下内容:public async Task DoSomethingAsync()
{
await DoSomethingElseAsync();
}
在这里,
DoSomethingElseAsync
返回 Task
这是等待和解开的。然后,一个新的Task
创建从 DoSometingAsync
返回.但是,如果相反,您将方法编写为:public Task DoSomethingAsync()
{
return DoSomethingElseAsync();
}
Task
返回者 DoSomethingElseAsync
由DoSomethingAsync
直接返回.这减少了大量的开销。 关于c# - ASP.NET Core 同步和异步 Controller 操作之间没有太大区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48015096/