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

297 天前
 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 更轻量。

10884 次点击
所在节点    程序员
193 条回复
lesismal
296 天前
@lesismal @kneo #100 只是举例子哈
lesismal
296 天前
@kneo

> 感情我只要“同意”就是人云亦云?和你意见不一样就是“底层知识不了解”?您了解底层也没看您说出来“golang 的 goroutine 是预分配固定大小 2kb 的内存”这种话啊。

前面说我不礼貌, 你不看为啥措辞这么火气, 因为你们阴阳在先
我假定你不懂这个那个, 也是因为这么没意义的测试, 你在那阴阳而且很赞同, 但凡基础知识够用也会对这个测试产生质疑和更多的理性探讨, 就像其他很多楼层的兄弟提到的那样, 草率觉得这个测试没问题同意测试结论, 大概率就是基础知识不够. 如果我的这个假定是错的, 那你再看看我#96 替你惋惜的吧

即使争吵, 我也真心祝你技术越来越进步, 这样可以避免大家以后更多争吵, 甚至会在同一个战线上同一个观点上去为别人厘清真相
james122333
296 天前
@kneo

如果是这样 那应该是 java 纯用线程不用虚拟线程对 go 开 goroutine 比较 这样两者相比才是正确的 因为文内 go 的使用方式就是错的 使用对方法 go 也是可以大幅降低内存使用 而且使用上更简单 java 标准库写的一坨的东西在 go 内写一点就可以了 两者运作方式相近才有可比性 除非 go 没提供 否则这样对比有失公允 go 这样的作法明显就是把细节留给用户 更有弹性 用户知不知道是用户的事
kneo
296 天前
@lesismal

> 即使争吵, 我也真心祝你技术越来越进步, 这样可以避免大家以后更多争吵

谢谢了。不过避免争吵不是靠谁技术进步,而是平等和包容的讨论问题。技术进步是为了保护自己下次别吵输了。
kneo
296 天前
@james122333

> 如果是这样 那应该是 java 纯用线程不用虚拟线程对 go 开 goroutine 比较 这样两者相比才是正确的

Java 的虚拟线程就是对标 goroutine ,这两个都是 green thread 。我不太明白为什么不应该比较。

> 因为文内 go 的使用方式就是错的 使用对方法 go 也是可以大幅降低内存使用

关于文中 Go 的使用方式错误能否具体点?
james122333
296 天前
@kneo

原因我在上面早就说了 这虚拟线程对标 go 应该是 goroutine+channel 你只用 goroutine 怎么可能达到一样效果 协程是微线程 没说一定得要负责负载小 文内作法就是有多少就是分散 cpu 资源并且增加内存使用
standchan
296 天前
@povsister #98 哈哈哈哈是的,我也看呆了。
james122333
296 天前
@kneo

如果按文内 go 这种写法套用在其它语言使用同样运作机制都是爆炸的 内存绝少不了的 真要对比应该是 java 用实体线程不开队列一样使劲开
kneo
296 天前
@james122333

> 虚拟线程是真实线程内用队列处理任务 其它的语言用事件驱动也是差不多道理 对标 golang 应该是 goroutine+channel

goroutine 也是在原生线程里 run 的啊……
james122333
296 天前
@kneo

但它并没有队列等机制确保负载不爆阿 等于 go 这部份你要自己做
james122333
296 天前
@kneo

文内 go 这样做法就雷同更迷你的 java 实体线程狂开而已 开更多但效果一样雷同 虚拟线程还有其它语言实作的还多做其它事情
kneo
296 天前
@james122333 抱歉,没能理解你说的 golang“没有队列等机制确保负载不爆阿”。

大家都是 green thread ,都需要去分配资源去占用原生线程。

你的说法听起来是在表达 golang 的调度机制不够优秀。但你说因此要 Java 换原生线程来比好像还差点说服力。
lesismal
296 天前
@james122333 @kneo

继续上点货, golang timer+简单的 goroutine pool:
https://gist.github.com/lesismal/aaf767b03f669908b1d5aae61a135a1c

goroutine pool 就是用 chan 的简单实现
timer 的是直接用的 B 站毛剑的这个单协程, 稍微改了下 timer 到时触发后用上面的 goroutine pool 去执行 func:
https://github.com/Terry-Mao/goim/blob/master/pkg/time/timer.go

具体需要多少 size 的 goroutine 自己设置, 10000 的并发度已经足够满足绝大部分需要了

m3 macos 简单跑了下:
1M task, goroutine pool size 10000, chan queue 1000, cost 115M
1M task, goroutine pool size 1000, chan queue size 1000, cost 95M

如果再改改时间轮之类的优化下海量 timer 的每个 itemsize, 还能再省些内存, 但是这个版本已经足够了
lesismal
296 天前
@kneo 其实吵吵挺好的, 不打不相识, 技术这种, 只要理性吵, 越吵道理越清晰, 而且很多技术路线之争, 即使是在老爷子们或者不同社区之间, 也是互相很多争吵, 争吵是因为没有一个完美的方案, 吵的多了, 改进多了, 就越来越好了
吵过了就都翻篇过去了, 以后咱也多多交流
CRVV
296 天前
goroutine 从来都不是协程。

在 go < 1.14 的版本里面,goroutine 的实现( implementation )确实是协程,但是它没有协程的接口( interface )。
因为实现一样,大家喜欢叫它协程,这也没什么错。
https://go.dev/doc/faq#goroutines
这里有明确的解释,把协程做了一点修改,起了一个新名字 goroutine 。当时肯定更不能叫 thread 因为不是抢占式调度的。所谓 interface ,那就是用来以后改 implementation 的,所以专门搞了一个新名字,这事他们团队做得很明确。

然后 1.14 把调度器改成了抢占式的。
https://github.com/golang/go/issues/10958
那这东西就完全不是协程了。

中英文的内容里面都有很多人习惯说协程、coroutine ,你非要说这是你的习惯要留着它,那就留着吧也没什么关系。
不过错的就是错的,别理直气壮地用错误词汇。
james122333
296 天前
@kneo

go 就是使劲狂分资源而已 你要自己分配资源 这部分语言没有义务一定要做
james122333
296 天前
@kneo

自己分配或靠第三方库帮你分配 有好处也有坏处
kneo
296 天前
@james122333 额,好吧,我还是维持我的观点。
sofukwird
296 天前
素养差一大节,你也能聊的下去,有点闲哦
james122333
296 天前
@CRVV

现在 go 的运作确实如同一般线程 但我觉得说协程也没什么关係

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

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

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

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

© 2021 V2EX