运行 100 万个异步并发任务需要多少内存

283 天前
 hez2010

去年有一个 “How Much Memory Do You Need to Run 1 Million Concurrent Tasks?” 的文章测试了各种语言在运行 1 个、1 万、10 万、100 万个异步并发任务下需要多少内存,不过当时测试的版本都很旧,代码里也多多少少有各种槽点,不能反映最新的情况。

这次把所有的语言版本都更新到最新,并且还加入了针对 GraalVM 、GraalVM native-image 和 .NET NativeAOT 的测试,然后修掉了之前被人指出代码中不对的地方,测了一个 2024 年版本的 “How Much Memory Do You Need in 2024 to Run 1 Million Concurrent Tasks?”。

可以在这里看详细测试: https://hez2010.github.io/async-runtimes-benchmarks-2024 。测试环境和代码也在里面有说明。

这里简单贴一下最终的测试结果:

1 个任务,测各语言 runtime 本身的 footprint:

1 万个并发任务:

10 万个并发任务:

100 万个并发任务:

Go 在最开始的时候内存占用很小,但是 Goroutine 的开销非常的大,随着并发任务的数量上升内存大量上涨,个人怀疑是 Go 的 GC 跟不上分配了,估计再接着增大并发数的话 Go 很可能会 OOM 。

Rust 则是发挥稳定,从始至终都表现着非常好的占用水平。

C# 的 NativeAOT 的表现则是直接把 Rust 比下去了,甚至随着并发数量的增大,到后期不做 NativeAOT 的 C# 内存占用都要比 Rust 更小了,可能是因为 tokio 和 async_std 在内存分配和调度这一块儿还有改进空间?

Java 的 GraalVM 表现要比 OpenJDK 差很多,而 GraalVM 的 native-image 表现就要好不少。另外就是忽略 GraalVM 的成绩的话,从结果来看 Java 的 Virtual Thread 要远比 Goroutine 更轻量。

10790 次点击
所在节点    程序员
193 条回复
INCerry
283 天前
看来还得是用 C#
nxcdJaNnmyF9O90X
283 天前
java 就是一坨屎 明眼人这么大的方案 肯定会有第三方池化方案 谁无脑原生的 go func(){}
PTLin
283 天前
经典半吊子 benchmark ,一个 sample 的代码,没有不同的场景,得出一个简单的结论。
kneo
283 天前
测的什么人家写的很清楚,因为 Go 结果不好看就破防说人误导不懂的也是很搞笑的。

以后但凡谁测了个东西出来,结尾是不是都得加一段您要是水平不够的话千万别看,您要是看了得出我没写的结论会有老家伙跳出来喷我说我误导您。当然哪怕您不看这些老家伙也会跳出来喷我说我误导您啦。
lbp0200
283 天前
所以结论是把 java 程序员都开除,改用 rust ?
lesismal
283 天前
@kneo 在这说我呢是吧? 你先看下 #6, 其他语言测试的方式的本质都是少量线程或者无栈协程/线程或者异步回调, 就 go 用有栈协程拿来对比, 你觉得公平? 我 #6 和其他几层里说的很清楚了, 这种测试 golang 你就直接 time.AfterFunc 占用直接省掉绝大部份, 甚至再订制下可以更省, 简单的正确的解题答案你不用, 非要用非常复杂浪费的方式去解答, 然后说 golang 语言不行?

> 测的什么人家写的很清楚

他出个测试他就专业吗? 他的测试方法正确吗?

说句不好听的, 你懂吗? 你懂多少?
系统, 底层知识不了解, 只知道看个半吊子脑残的老外的 blog 就在那人云亦云? 还很自豪?

要讨论辩论技术就拿出真材实料来聊技术的这些点, 我的输出都是围绕这个事情本身讲清楚原因和答案, 你在这需空打靶只输出一点阴阳的词语, 丝毫技术的论点论据都没有, 好意思出来讨论?
我说的技术点知识点你可是丝毫不看, 只看我一句观点的就给我扣帽子是吧?
就是你们这种人多了, 才把技术讨论搞得乌烟瘴气!

送你一句: 菜就多练, 不懂就学, 否则就少出来丢人现眼
xiaocaiji111
283 天前
看了上面一些评论,不能不说 go 牛逼,社区全是高 star 残废方案叫轻量,叫简洁,实现一些逻辑,全部要手动,要绕弯,一坨坨代码叫可控,解决方案内网外面找不到任何说明和文章的叫流行。写了几年社区电商 go 后端的肺腑之言。
lesismal
282 天前
@xiaocaiji111
所以你自己或者你曾经呆过的团队的 go 方案不好, 就是 go 不好是吗?
在 java 电商系大量人才, java 大量成熟社区方案的前提下, 为啥还有大量新公司新业务用 go 有思考过吗?
java 的繁冗, 面向对象顶层设计面对快速迭代的业务频繁变更的需求时的无力你是没考虑过吧?
大中小厂的负责技术的人带头把很多业务/项目尽量往 go 上转, 这些人都不如你是吧?

go 的人力不如其他语言那么多, 很多人是其他语言转过来没那么多经验带着其他语言的舒适圈非要照猫画虎用错误的方式写 go 或者找 go 里对应其他语言的解决方案, 姿势都错了还拿来当道理, 你自己想下合理吗? 什么叫入乡随俗, 用 go 来请用 go 的方式不懂吗? 那我反过来问一句, go 的协程和 chan 这么方便, 我用习惯了, 换到其他语言里都没有 go 的协程和 chan, 其他语言也太垃圾了! 你说这合理吗?

很多不够专业的 gopher 组成的团队踩坑积累经验很正常, 等这部分人都熟练了再拿来对比说事, 而且说事也应该区分一些, 比如各自语言解决了哪些问题. 多了不说, go 解决的很多其他语言的性能问题, 明星企业大量拥抱 go, 和着在你们眼里都不合理是吧, 这种眼界就真的适合留在 curd 的舒适圈或者小项目里养老算了, 但凡有大点的项目性能要求高的方案都解决不了, 只能等着上面的人出了方案给你们然后你们照着实现. 怪不得叫 IT 民工
xiaocaiji111
282 天前
@lesismal 幼稚且可笑,睁眼看看世界吧,盯着一两个语言特性,觉得这就是世界全部了?搞得别人好像没接触过一样。
lesismal
282 天前
@xiaocaiji111 和前面那位一样, 只评论和阴阳, 丝毫不讲技术的点了是吧? 要是只想搞搞 curd, 用 curd 的思维思考技术和工程, 只需要挣钱养家不求技术发育, 那我祝你幸福, 咱们大路朝天

懒得浪费时间, 如果后续再有想阴阳的人, 建议/请先认真看下我前几层的回复
kneo
282 天前
@lesismal 没针对您哦,说的是一种懂一点东西就瞎咋呼的人,虽然也包括您。不过并不想跟您这种素质不咋样的人对线,您还自己 at 上来。

看您一个劲儿贴自己的库,想骗 star 是吧。我看了一眼,请问您这写个破库是干嘛的呢?能解决人家说的一百万个并发任务吗?不会是解决不了得靠排队了吧。您不会想说现实中大家都是排队的吧?您不会说别人不排队就能轻松并发是作弊,毫无意义吧?

说句不好听的,您连别人测的是啥都看不懂。人家的百万并行任务和你的百万连接是一个东西吗。但是不影响你有个什么破库,在那 BB 好像自己懂似的。在那一顿输出自己的“真才实学”,一边喷人“毫无意义”,一边证明 go 不行得靠你的破库,用你的“真是场景”带乱别人的客观测试,还有啥用啊?我看没你人家讨论的挺好。
ykrank
282 天前
学个语言学得像粉圈和宗教一样。对,我说的就是上蹿下跳的那位,绕着绕着就开始推销自己的实现了,这就是粉圈头子吧
mightybruce
282 天前
怎么又有人拿着一个半吊子搞的 benchmark 来说事,
这个人连 Node.js golang 几个语言都写不好,也不懂如何平行比较,别再发这些玩意了。
lesismal
282 天前
@ykrank #32

> 学个语言学得像粉圈和宗教一样

宗教的问题我上面说过了, 我聊的都是技术干货, 你这评论不能说是没有技术的干货, 只能说事和技术点毫无关系, 而且是属于扣帽子.

> 对,我说的就是上蹿下跳的那位,绕着绕着就开始推销自己的实现了,这就是粉圈头子吧

go 社区暂时没有其他完整方案, evio gnet gev 之类的他们都只支持少量功能, 都不支持 tls http 之类的这样完整的功能, nbio 暂时算是独一份
推销就是错吗? 把好的方案分享给别人, 总比你这种什么干货不输出上来就是阴阳扣帽子强吧? 而且我的项目已经有很多用户确实改造优化带来了提升, 这是坏事情?
另外, 我也很久没发单独的帖子来推广了, 不需要这个 KPI 挣钱, 所以比较佛系, 但是看到相关的提一嘴, 怎么了, 你是想让别人都闭嘴不能说自家的好是吗? 你可真是霸道呢, 你咋不去当总统呢?
mightybruce
282 天前
搞几个简单的测试就能当 benchmark 也是搞笑, 这种垃圾测试有什么价值,至少也要搞点有意义的比如
并行 Mandelbrot 集合绘图 这种吧。
业余程序员搞的不专业测试,然后转载了再来看?
mightybruce
282 天前
就这傻缺 benmark 搞几个系统调用 sleep 也配叫异步并发任务,还不如研究哪个语言对于这种无意义的等待情况的优化
sagaxu
282 天前
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking


fun main(args: Array<String>) {
println("stated")
runBlocking {
val numTasks: Int = args[0].toInt()
for (i in 1..numTasks) {
launch { delay(30_000) }
}
println("launched")
}
println("finished")
}

Kotlin + OpenJDK 21 ,1M 个协程 488M 内存(RSS)
ebony0319
282 天前
```java
public static void run(){
int taskNums=100000000;
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
try {
Thread.sleep(Duration.ofSeconds(10));
} catch (InterruptedException e) {
}
});
}
}
```
java 应该这样写 1 亿 50m 。ExecutorService 已经实现了 AutoCloseable 接口,会等所有任务结束释放。
xiaocaiji111
282 天前
@lesismal 不想跟你对线,你要是觉得语言就只有一些特性就很牛,或者后端只有 curd ,我也不想反驳。建议去大公司体验下,看一个系统除了 curd 以外到底有多少其他技术,或者去看看 JCP 每次的提案有多少新技术,另外我不评价哪个语言好,哪个语言坏,谁工作中只会只用一门语言的。每个场景都有自己最优的选择。只是看不惯上来就无脑说别人拉踩的,反而显得自己是个小丑。
wysnxzm
282 天前

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

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

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

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

© 2021 V2EX