C# 中的嵌套等待对性能的影响
Nested awaits in C# impact on performance
我在 Api 中公开了一个方法,该方法预计每秒有 500 次点击。
我已将所有 API 设置为异步响应。
每个请求中可能有多个数据库调用,应该是异步的还是同步的。
我的观点是嵌套等待,比方说 3 层。
在这种情况下,它会提高性能还是上下文切换会严重影响性能。
我搜索得够多了,但我越来越困惑了。
应该有一些我想遵循的经验法则。
同样在底部,数据库调用是同步调用,我不能像已经写的那样做很多事情。
await
的数量通常并不重要。如果您发现性能不合适,您可以做一些事情(例如,使用 ValueTask<T>
而不是 Task<T>
)。
然而,最大的性能问题是:
on the bottom, the database call is sync call
如果低级调用是同步的,那么您可能会遇到可伸缩性问题。如果当前代码正在执行“异步优于同步”(例如 Task.Run
或 Task.Factory.StartNew
),那么这将是一个问题。要么将代码更改为“一直异步”(即,使数据库调用异步)并接受需要完成的额外工作,要么将其更改为一直同步并接受同步解决方案的有限可扩展性.
异步编程(即协程的使用)的目的不是引入性能增益,而是在不使用它们时改善计算资源。每使用 await
,引入一个“检查点”,执行可能会被“暂停”。
虽然您的逻辑代码处于“暂停”状态,但底层线程并未像在同步执行模型中那样处于休眠状态。这对于可以有多个并发请求的基于(网络)服务的 API 至关重要:当一个请求正在等待 IO(网络或本地)时,底层线程仍然可以处理另一个请求,从而提高 整个服务。每个请求不会获得任何好处;确实,当编译器将您的代码重写到状态机中以处理“暂停”和“恢复”时,它会增加一些开销。
因此,除了基准测试之外,您还应该选择分析的粒度。
我在 Api 中公开了一个方法,该方法预计每秒有 500 次点击。
我已将所有 API 设置为异步响应。 每个请求中可能有多个数据库调用,应该是异步的还是同步的。
我的观点是嵌套等待,比方说 3 层。 在这种情况下,它会提高性能还是上下文切换会严重影响性能。 我搜索得够多了,但我越来越困惑了。 应该有一些我想遵循的经验法则。
同样在底部,数据库调用是同步调用,我不能像已经写的那样做很多事情。
await
的数量通常并不重要。如果您发现性能不合适,您可以做一些事情(例如,使用 ValueTask<T>
而不是 Task<T>
)。
然而,最大的性能问题是:
on the bottom, the database call is sync call
如果低级调用是同步的,那么您可能会遇到可伸缩性问题。如果当前代码正在执行“异步优于同步”(例如 Task.Run
或 Task.Factory.StartNew
),那么这将是一个问题。要么将代码更改为“一直异步”(即,使数据库调用异步)并接受需要完成的额外工作,要么将其更改为一直同步并接受同步解决方案的有限可扩展性.
异步编程(即协程的使用)的目的不是引入性能增益,而是在不使用它们时改善计算资源。每使用 await
,引入一个“检查点”,执行可能会被“暂停”。
虽然您的逻辑代码处于“暂停”状态,但底层线程并未像在同步执行模型中那样处于休眠状态。这对于可以有多个并发请求的基于(网络)服务的 API 至关重要:当一个请求正在等待 IO(网络或本地)时,底层线程仍然可以处理另一个请求,从而提高 整个服务。每个请求不会获得任何好处;确实,当编译器将您的代码重写到状态机中以处理“暂停”和“恢复”时,它会增加一些开销。
因此,除了基准测试之外,您还应该选择分析的粒度。