dotnet 开发 API 的时候使用 asyn 、await 有什么优势吗

2019-11-06 15:44:22 +08:00
 daijinming

如果一个 API 被标记为 asyn,和 没有 asyn 的 api 有什么区别?不是太理解,这个和多线程有关系吗,求教

3917 次点击
所在节点    程序员
29 条回复
crclz
2019-11-08 00:52:03 +08:00
回复测试
crclz
2019-11-08 00:59:31 +08:00
@xingheng 同步方法可以直接执行 DoSomethingAsync(),不用 await。所以就只会存在一个线程(或者几个)不断地接受请求、将请求传至 pipeline,经过各种中间件。从第一个中间件开始,就已经是 async 方法。另外我推测应该是直接调用的 DoSomethingAsync(),不加 await。我再在下文说一下何为“高效管理”。

@xuanbg 并发量和 cpu 核心数的关系粗略的来说是呈线性关系,但具体的下文讲。

先从数据库连接池的最佳大小说起。
连接池的最佳大小:connections = (core_count * 2) + effective_spindle_count。core_count:核心数; effective_spindle_count=貌似是有效磁盘数量。很久以前读的文章,记不太清。
https🐎github.com🐎brettwooldridge/HikariCP/wiki/About-Pool-Sizing
crclz
2019-11-08 00:59:44 +08:00
这篇文章中貌似还说,其实所有类似的(例如线程池,选择最佳的线程池大小),也基本适用于这个公式。
也就是说,线程池的大小有一个最优的大小。在这个最优的大小下,你的吞吐量、响应时间最优。

这个最优的大小由 C#管理,程序员不用操心。

而 C#的 Task 是什么? Task 可以简单的理解为“任务”。你不用关心这些“任务”是如何完成的,你只需要知道:可以用 DoSomethingAsync()来开启一个 Task (并获得该 Task 实例)、可以用 await SomeTask 来等待 Task 结束。至于如何完成 Task 的任务,则是 c#的事情——c#会高效利用线程池里的资源,来完成“任务”:在 await 一个阻塞性的 task 时,没有线程会被拿来等待(这也是传统多线程方式无法企及的)。一个 Task 可能会先后被 1 个、2 个、5 个或者多个 worker thread 接手,但这些东西开发者都不需要关心。又由于线程池里 worker thread 的数量设计很合理,所以这种方法能达到最优的表现。

唯一的缺点就是,要严格控制代码(或许 VS 的各种 analyzer 包能容易的做到这一点),不能出现传统的同步阻塞式方法 例如 File.Read();而是要将它们全都换成 await File.ReadAsync()这种。因为线程池的 worker thread 资源是很宝贵的:核心*2+硬盘数,在 4 核 cpu 下,这个值仅仅为 9。c#可能有一套更优的公式,但也离这个值不远。一旦 worker thread 中运行了同步阻塞式代码,宝贵的线程池资源会被浪费。可能造成 threadpool exhaustion 等问题(这个我不是很懂),但至少会让吞吐量下降到 线程池大小 /响应时间。

相比来说,感觉 go 的并发代码编写方式、内部实现都很可以。希望 .Net Core 早日达到 go 的性能。
crclz
2019-11-08 01:01:13 +08:00
@xingheng @xuanbg 回复一直发不出来,截断后发出来了。
loqixh
2019-11-08 09:53:31 +08:00
@crclz 吐血, asp.net core 一直超过 go 的网络性能啊........虽然比不上 java 的 netty 但是 Netty 用得人不多, 所以日常来说.net core 性能基本是最高之一
crclz
2019-11-08 10:06:41 +08:00
@loqixh 网上我看过一些评测,发现都是 go (的某个框架)优于.net core
loqixh
2019-11-08 10:18:01 +08:00
@crclz 因为都是用玩具框架对比.net core 的全功能框架,就算这样 go 的性能也就比.net core 高 10%-20%的样子, 真正实用性能可以看 aws lambda 的性能测试.net core 是其中最高的
xingheng
2019-11-08 14:29:16 +08:00
@xuanbg 你说得对,是我上面对“并发量”的描述不对,应该算 keepalive connection/request 比较准确。
xingheng
2019-11-08 15:05:31 +08:00
@crclz 学习了。我单独去查了一下“effective_spindle_count”的几篇文章,你说的 connection pool 大小是指的数据库层面的,不是 http/tcp connection 的。我觉得跟题主说的 API 层面上的 async 不太对等。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/616879

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX