V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
hez2010
V2EX  ›  程序员

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

  •  1
     
  •   hez2010 · 27 天前 · 8980 次点击

    去年有一个 “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

    1 万个并发任务:

    10K

    10 万个并发任务:

    100K

    100 万个并发任务:

    1M

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

    第 1 条附言  ·  26 天前

    原文中给 Rust 追加了一个把 join_all 换成了循环依次等待的测试用例,tokio 的占用直接被砍半,成为占用最小的那一个。async_std 由于需要 poll 才能被调度因此无法这么做。

    tokio-for

    第 2 条附言  ·  22 天前

    接受了几个社区提交的代码改进,然后加上了执行时间和 CPU 占用结果,新的结果如下:

    https://hez2010.github.io/async-runtimes-benchmarks-2024/take2.html

    里面所有的结果图都可以通过点击具体的标签(Memory、CPU、Time)来隐藏某类数据,这样方便你针对一类项目来进行对比。

    简单放一下结果:

    minimal

    10K

    100K

    1M

    注意 Java 和 Python 在 1M 的时候已经无法在 10 秒内完成 benchmark 了,而其他语言都能正常在 10 秒内完成。

    192 条回复    2024-12-05 10:16:51 +08:00
    1  2  
    test0x01
        1
    test0x01  
       27 天前 via Android
    有意思
    001kh
        2
    001kh  
       27 天前
    1 秒 10 个块的 Rust ,25 q1 发布 via kaspa
    lesismal
        3
    lesismal  
       27 天前   ❤️ 8
    1. 实际场景里也不可能全是 cpu 消耗的 task, 所以 sleep 类型的 task 是合理的
    2. 并发度极大超过系统核心数量的情况下, go 全用标准库直接 go func()是不公平的, 因为协程数量太大了, 这种完全可以优化成 size 可控的协程池, sleep 可以 timer 回调
    3. 如果 sleep 是为了模拟实际场景里的 io 消耗例如网络 io, go 标准库主要是提供同步 io 接口, 那么多数需求确实需要每个 conn 一个协程, 但是, 你可以选择不用标准库, 例如我的 nbio, 百万连接 websocket echo 1k payload 压测, server 部署在 4c 8g ubuntu vm 上, 实际内存占用可以控制到 1g 以内:
    https://github.com/lesismal/go-websocket-benchmark?tab=readme-ov-file#1m-connections-1k-payload-benchmark-for-nbiogreatws

    请注意, 3 里说的百万链接占用 1g 内存, 比 OP 的这种简单 task 占用多, 不代表相同 task 测试优化后的方案就比其他语言多这么多.


    另外, 不同语言的这个测试, OP 用的都是未经优化的方式, 方案并不是好的解决方案, 所以这个测试本身就是不合理的.
    比如, 如果只是用这种 sleep task, go 直接用 for { time.AfterFunc() } 占用很低的. 但我相信这并不对应任何实际应用场景.

    毫无意义的测试, 却顺便拉踩, 捧 java 踩 go, 实在看不下去了我才必须出来澄清下.
    server
        4
    server  
       27 天前
    go 可以试下潘少的 ants
    hez2010
        5
    hez2010  
    OP
       27 天前   ❤️ 5
    @lesismal

    > 毫无意义的测试, 却顺便拉踩, 捧 java 踩 go, 实在看不下去了我才必须出来澄清下.

    跟 Go 的 goroutine 同样是 green thread 方案的 Java virtual thread ,在并没有做任何池化的情况下,只是简单的 new Thread ,在 1M tasks 占用确实比 goroutine 小了很多,这难道不能说明 goroutine 的资源占用确实不佳吗?

    况且文章前面也肯定了 Go 在轻量负载时的占用小、否定了 Java 在轻量负载时的占用大,怎么就能被理解成踩一捧一?
    如果你认为 Go 就是天下第一,一切 Go 表现不好的测试都是因为测试不好,而 Go 没有任何问题的话那我也没话说。况且这测试也不是我设计的。
    lesismal
        6
    lesismal  
       27 天前
    试了下这个:
    var wg sync.WaitGroup
    for i := 0; i < 1000000; i++ {
    wg.Add(1)
    time.AfterFunc(10*time.Second, func() {
    wg.Done()
    })
    }
    wg.Wait()

    macos m3 占用 150M, 应该是有不少定时器到时然后并发创建的 goroutine 较多
    如果改用时间轮或者堆的定时器, 数量可控的协程池, 这个占用会降更多.

    @server 可以看下这个帖子: /t/1089474
    实际对比下其他的看看, 我和一些朋友测试, ants 跟其他实现方式相比没有优势, 甚至是劣势, 以及实现复杂可能存在的不确定性
    grzhan
        7
    grzhan  
       27 天前   ❤️ 2
    如 @lesismal 老板所说,这里 golang 的开销应该是有栈协程的开销,一个 goroutine 栈默认最小是 2K ,1000,000 * 2K / 1024 / 1024 = 1.9G ,算上 sudog 等其他的结构加起来可能差不多吧。

    实际 golang 处理异步任务的时候确实不会开这么多协程,更多是把协程池化然后基于 channel 通信来处理。

    在实际 Golang 开发过程中确实会有每个 conn 对应一个 goroutine 大量连接导致内存过高的 case ,然后社区里确实有对应魔改 netpoll 以及 nbio 这样的方案来解决类似的问题。
    grzhan
        8
    grzhan  
       27 天前
    我觉得不一定是拉踩,针对 Golang 的这一情况可以添加更多的说明会好一些。
    grzhan
        9
    grzhan  
       27 天前   ❤️ 1
    @lesismal 所以一般定时要求不严格的话很多 Golang 开源项目会给定时 duration 加个 10% 左右的随机抖动吧
    例如 VictoriaMetrics 的 timeutil.AddJitterToDuration - https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/lib/timeutil/timeutil.go
    lesismal
        10
    lesismal  
       27 天前   ❤️ 1
    @hez2010 #5

    这个确实是毫无意义的测试, 你可以看下 #6, 当然, 其他语言也一样可以不用虚拟线程或者协程之类的, 都没必要用这么多内存. 但文章却非要选择使用虚拟线程和协程来对比, 然后海量的有栈 goroutine 就劣势了, 这不搞笑呢嘛

    > `从结果来看 Java 的 Virtual Thread 要远比 Goroutine 更轻量。`

    这个是文章里的结论之一, 用错误的测试方法, 得出一个作者想要的`正确`结论, 有意思?
    别说什么都各自有褒贬, 方法和结论都不正确的前提下, 褒贬也都是不准确的. 然后这个所谓的结论对于大多数读者而言, 就是 java 的虚拟线程更优秀, 这本身算不算误导就各自琢磨吧

    > 如果你认为 Go 就是天下第一,一切 Go 表现不好的测试都是因为测试不好,而 Go 没有任何问题的话那我也没话说。

    我可从来没说过这个, go 标准库海量并发占用高我自己就知道, 所以我才搞 nbio 之类的方案优化, 而且相对成熟了, 可以替换标准库方案, 但是你们非要"只用标准库方案"的方式来评价整个 golang, 就不合理了

    > 况且这测试也不是我设计的。

    那你可以看下我的观点, 顺便多思考下, 避免只看表象, 避免不知其中深意, 避免人云亦云

    这个测试如果是哪个老外设计的, 那他是不专业的, 我本来也是说这个测试而不是针对你
    lesismal
        11
    lesismal  
       27 天前   ❤️ 1
    @grzhan #9

    > 所以一般定时要求不严格的话很多 Golang 开源项目会给定时 duration 加个 10% 左右的随机抖动吧
    例如 VictoriaMetrics 的 timeutil.AddJitterToDuration -

    通常的定时功能没必要加抖动, 这个库的具体内容我没看. 定时加抖动有可能是为了避免同时创建大量具有相同超时时间的内容, 后续同时到期去创建大量协程异步删除内容导致 goroutine 过多造成不稳定, 或者其他什么特殊的需要
    hez2010
        12
    hez2010  
    OP
       27 天前
    @lesismal #10

    > 我可从来没说过这个, go 标准库海量并发占用高我自己就知道, 所以我才搞 nbio 之类的方案优化, 而且相对成熟了, 可以替换标准库方案, 但是你们非要"只用标准库方案"的方式来评价整个 golang, 就不合理了

    标准库目前有计划改善这个问题吗?毕竟标准库用起来最简单,如果标准库能解决这个问题的话那岂不是不需要 nbio 这类的方案优化了。
    另外看了一眼 nbio ,似乎是针对 client-server 网络场景特化的,牺牲了通用性。例如通过 goroutine 来代替多线程进行并行计算也是一个有效的场景。
    grzhan
        13
    grzhan  
       27 天前   ❤️ 1
    @lesismal #11

    > 通常的定时功能没必要加抖动, 这个库的具体内容我没看. 定时加抖动有可能是为了避免同时创建大量具有相同超时时间的内容, 后续同时到期去创建大量协程异步删除内容导致 goroutine 过多造成不稳定, 或者其他什么特殊的需要

    应该是这样,像 Kubernetes 项目里也会用到很多 Jitter 去避免相同的超时时间( https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/wait/backoff.go#L203 ),像 kubelet , 以及几个组件的 LeaderElection 都会用到,确实还蛮常见的。
    lesismal
        14
    lesismal  
       27 天前   ❤️ 2
    @grzhan #8
    可能作者本意不是拉踩, 或者不是故意拉踩. 但不正确的方法, 得出的结论就会误导很多人. 因为绝大部分开发者不了解系统知识, 不了解不同语言在这个不适合的测试场景与实际应用中的区别, 却给他们造成了错误的印象——例如 java 虚拟线程优秀, 然后可能误解 java 就是比 go 好.

    刚看了下文章作者的 github, 主要是 rust java, 所以可能他自己也是默认偏好 rust 和 java 多些, 所以也没考虑过要对 go 的做多一些说明吧, 非故意的默认的放纵某些他以为的`正确`结论
    所以我出来澄清一下

    OP 或者其他人不要误解, 这并不是 go 邪教, 而只是实事求是
    如果有人说 go 性能比 c/cpp/rust 强, 我要是有时间有兴趣也是会出来反驳的, 所以请 OP 或者其他人不要拿"我认为"golang 天下第一"说事
    lesismal
        15
    lesismal  
       27 天前
    @hez2010

    > 标准库目前有计划改善这个问题吗?毕竟标准库用起来最简单,如果标准库能解决这个问题的话那岂不是不需要 nbio 这类的方案优化了。

    如我前面提到的, 标准库目前的 net.Conn 这些只提供了阻塞的 io 接口, 除非是特别简单的场景, 否则没法避免一个连接一个协程. 例如读, 不一定什么时候读到一个完整 request, 就只能阻塞在那等待, 这就需要占用一个协程.

    > 另外看了一眼 nbio ,似乎是针对 client-server 网络场景特化的,牺牲了通用性。例如通过 goroutine 来代替多线程进行并行计算也是一个有效的场景。

    nbio 的 http 与标准库基本兼容, 写法和标准库基本一样的:
    https://github.com/lesismal/nbio-examples/blob/master/http/server/server.go

    少量特殊情况不能像标准库那样, 例如 nbio 的 epoll 部分负责的 conn 是非阻塞的, 不适合拿去像标准库那样 io.Copy.
    因为 nbio 本来就是为了避免持续占用协程, 如果还像标准库那样提供阻塞的 io 接口可以去 io.Copy, nbio 就没有意义了
    lesismal
        16
    lesismal  
       27 天前   ❤️ 3
    @grzhan #13

    嗯嗯

    > 以及几个组件的 LeaderElection 都会用到,确实还蛮常见的。

    election 这种, 我记得不太清楚了, 但好像记得个大概.
    分布式一致性算法里的选举, 通常要避免各个节点都在相同的时间参选(发出自己选举的协议给其他节点), 因为如果大家都同时参选, 同时以相同的概率获得其他人的选票, 就会更难选出 leader.
    所以在参选过程中, 例如启动, leader 掉线时的重新选举, 或者选举失败时的重选, 是可以每个节点自己随机一个时间抖动来尽量避免选举冲突的
    xiaokangz
        17
    xiaokangz  
       26 天前 via iPhone
    可以考虑使用折线图📈,放在一张图里看的更清楚
    bthulu
        18
    bthulu  
       26 天前   ❤️ 1
    这难道不是在捧 C#, 不知道你们怎么理解成捧 java 的
    tiredtom
        19
    tiredtom  
       26 天前
    Metatron7
        20
    Metatron7  
       26 天前
    C#用 Valuetask 会不会更低一点
    INCerry
        21
    INCerry  
       26 天前
    看来还得是用 C#
    xingjue
        22
    xingjue  
       26 天前   ❤️ 1
    java 就是一坨屎 明眼人这么大的方案 肯定会有第三方池化方案 谁无脑原生的 go func(){}
    PTLin
        23
    PTLin  
       26 天前   ❤️ 1
    经典半吊子 benchmark ,一个 sample 的代码,没有不同的场景,得出一个简单的结论。
    kneo
        24
    kneo  
       26 天前 via Android   ❤️ 4
    测的什么人家写的很清楚,因为 Go 结果不好看就破防说人误导不懂的也是很搞笑的。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    go 社区暂时没有其他完整方案, evio gnet gev 之类的他们都只支持少量功能, 都不支持 tls http 之类的这样完整的功能, nbio 暂时算是独一份
    推销就是错吗? 把好的方案分享给别人, 总比你这种什么干货不输出上来就是阴阳扣帽子强吧? 而且我的项目已经有很多用户确实改造优化带来了提升, 这是坏事情?
    另外, 我也很久没发单独的帖子来推广了, 不需要这个 KPI 挣钱, 所以比较佛系, 但是看到相关的提一嘴, 怎么了, 你是想让别人都闭嘴不能说自家的好是吗? 你可真是霸道呢, 你咋不去当总统呢?
    mightybruce
        35
    mightybruce  
       26 天前   ❤️ 2
    搞几个简单的测试就能当 benchmark 也是搞笑, 这种垃圾测试有什么价值,至少也要搞点有意义的比如
    并行 Mandelbrot 集合绘图 这种吧。
    业余程序员搞的不专业测试,然后转载了再来看?
    mightybruce
        36
    mightybruce  
       26 天前   ❤️ 1
    就这傻缺 benmark 搞几个系统调用 sleep 也配叫异步并发任务,还不如研究哪个语言对于这种无意义的等待情况的优化
    sagaxu
        37
    sagaxu  
       26 天前
    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
        38
    ebony0319  
       26 天前
    ```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
        39
    xiaocaiji111  
       26 天前
    @lesismal 不想跟你对线,你要是觉得语言就只有一些特性就很牛,或者后端只有 curd ,我也不想反驳。建议去大公司体验下,看一个系统除了 curd 以外到底有多少其他技术,或者去看看 JCP 每次的提案有多少新技术,另外我不评价哪个语言好,哪个语言坏,谁工作中只会只用一门语言的。每个场景都有自己最优的选择。只是看不惯上来就无脑说别人拉踩的,反而显得自己是个小丑。
    wysnxzm
        40
    wysnxzm  
       26 天前   ❤️ 4
    mightybruce
        41
    mightybruce  
       26 天前   ❤️ 1
    @xiaocaiji111 你不过是螺丝钉而已,别往脸上贴金了, 我他妈笑死了, 这些技术和大公司搞的框架有一个是你搞的,十多年前,java 也没多少解决方案,恰恰那时候是 java 的黄金期
    realpg
        42
    realpg  
       26 天前   ❤️ 1
    你愿意用 java 你就用 java

    反正高并发,我有权进行选型,肯定用 golang 不用 java 的

    golang 的高并发项目从来都是内存显得没地方用很闹心,被迫每个 4C8G 的机器就都开个 redis cluster node 省的内存空着看着难受

    java 。。。java 的项目组动不动就先开个 64G 内存 然后过一阵子再加到 128G 256G

    以上没有任何理论支撑 纯纯自己基于实际情况总结 如果你有异议 那你说得对
    realpg
        43
    realpg  
       26 天前   ❤️ 1
    实际经验就是:

    高并发场景,golang 是指数级的省内存,而且没有那么多经验需要遵守,也不需要去调虚拟机参数

    弄只猴子过来都能在一个 4C8G 的节点 写 10K QPS 的 api 服务,而且很多时候,内存都不如 VM 里面的监控用的多
    chenxuuu
        44
    chenxuuu  
       26 天前
    @wysnxzm 你怎么可以这么揭穿他人的双标发言呢,弄得大家多尴尬啊
    qcbf111
        45
    qcbf111  
       26 天前   ❤️ 1
    @bthulu 因为 c#不用捧,公认的在 gc 语言中性能最好的一档,语法最优先的之一,奈何早期愚昧失去了生态。语言潜力甚至让 unity 在 c#里面搞了个类 c 语言( dots ecs )。
    比他性能高的没他好用,和他差不多好用的没他性能高。
    xiaocaiji111
        46
    xiaocaiji111  
       26 天前
    @mightybruce 那你就笑死吧,看看 go 除了云原生那些领域,其他哪个解决方案不是餐费的,要么几年不维护,再者有多少经过大公司考验的?除了 cncf ,有几个基金会?有多少行业解决方案,对,没有就是简单。
    另外我说了,除了 curd 有很多技术,并没有说是 java ,单单 java 很多也是完不成的,或者说不是好的解决方案。不要为了黑而黑,硬往踩 java 拉 go 上靠。
    csys
        47
    csys  
       26 天前   ❤️ 1
    go 吃了 goroutine 设计的亏吧
    goroutine 有最小内存负担

    nodejs 的 promise 和 C#的 Task 都是简单对象,内存负担很小

    tokio 就不太清楚了

    这个 benchmark 最不好的地方在于,任务太不实际了,10s 空转,任务本身没有内存负担,又是高耗时
    如果一个任务本身的内存负担比较大,那 goroutine 的最小内存负担相对来说就不那么明显了
    实际场景里,真正关注的还是吞吐/内存效率
    palfortime
        48
    palfortime  
       26 天前 via Android
    没有人介绍一下为什么 c#这么优秀吗?
    berchtesgaden
        49
    berchtesgaden  
       26 天前
    假设一个 Java 虚拟线程的初始栈也设置为 2K ,100 万个虚拟线程也要用到近 2G 了,为什么这个测试中 Java 只用了 1G 出头?是因为初始栈更小吗?还是测试代码被优化后分配了更少的栈空间?
    wysnxzm
        50
    wysnxzm  
       26 天前
    nikenidage1
        51
    nikenidage1  
       26 天前
    @palfortime 知乎作者原文里有介绍

    自古以来的服务器应用都是一台服务器跑一个 server app ,然后让 server app 最大化内存占用,用空间换时间,一台机器撑起大量的流量。所以你会看到 Java 、老版本的 .NET 在 server 上动辄几个 G 的内存占用。
    毕竟向操作系统频繁申请和归还内存是一件很消耗性能的事情,因此很多语言都更倾向于一次性 commit 大量内存,然后留着自己管理,即使有可用空间也不会立即进行 decommit 。这样一来当有瞬时的大量内存需求时可以快速地将内存提供给负载用,提升整体性能。
    然而云原生时代一切都变了,每一个 server app 都跑在了容器上,由 k8s 等来调度,一台服务器上可能会跑很多的 server app 容器,这就使得以前那种用大量空间换时间的做法失效了:因为占用的资源越少意味着能够调度的容器越多,同时也意味着更容易进行横向扩展,灵活性变的更高。而以前的用空间换时间的做法在云原生时代反而是个累赘。
    .NET 自然也是要适应时代变化,因此大概两三年前就开始新的 GC 的设计和实现工作。到了 .NET 9 这项工作终于迎来正式发布,引入了新的 DATAS GC 代替原有的 Server GC 。
    这个新的 GC 可以根据实际的应用程序负载来动态调节所需的内存,在不需要的时候快速将多余的内存归还给操作系统,从而大幅度削减内存占用。
    然而 GC 并不能坐时光机预测未来的负载如何变化,因此 DATAS GC 下了大量的功夫去设计各种 heuristics ,从而能正确的预测和调节各托管堆大小,让申请下来的内存和实际需要的内存尽可能一致,据说这些 heuristics 甚至用了机器学习来优化过。
    在实际测试结果中,DATAS GC 相比原来的 Server GC 节省了 70%~90% 的内存,原来要 1G 内存的 server app 现在只需要不到 200mb 。官方给出的 ASP .NET Core 的 TechEmpower JSON benchmark 测试中,内存占用相比原来更是直接暴降了 93%,直接从原来的 1.6G 降到了现在的 120mb ,要知道 TechEmpower 可是大量并发的压力测试:
    pvnk1u
        52
    pvnk1u  
       26 天前
    @palfortime C#一直很优秀,大神 Anders 的作品,只是吃了出身和早期闭源的亏,要不然哪有 Java 的事,C#可是同时有着 Java 继任者 Kotlin 一样优雅的语法和 JVM 性能的语言
    nikenidage1
        53
    nikenidage1  
       26 天前
    不是,你怎么看出来是捧 JAVA 的啊
    kneo
        54
    kneo  
       26 天前
    @csys 我觉这个 benchmark 最有价值的地方就是用 10s 的 sleep ,这样测出来的就是 goroutine 的开销。既然是 benchmark ,我们当然是要得出一个能量化的东西。

    有些一直在喷场景不真实的,只能说是顾左右而言他。

    最搞笑还有个分享干货教人用 time.AfterFunc 的,拼了命的告诉大家不要在 golang 里同时创建这么多 goroutines 。简直是高级黑。
    Gilfoyle26
        55
    Gilfoyle26  
       26 天前
    我觉的应该搞成那种公开的挑战赛,规定条件,然后不限语言,类似于游戏的全球排名,然后让个路神仙自由发挥,你行就你上,公开代码,这样大家就没话说了。划定圆圈,自由发挥才是正确的路。
    james122333
        56
    james122333  
       26 天前 via Android
    这样比确实不太公平 虚拟线程是真实线程内用队列处理任务 其它的语言用事件驱动也是差不多道理 对标 golang 应该是 goroutine+channel
    而 java 内部实现複杂多了 按照惯例 java 依然是写的一坨... 简洁清爽一点更好
    CEBBCAT
        57
    CEBBCAT  
       26 天前   ❤️ 1


    昨天晚上就看见了,当时看见 lesismal 和楼主的交流感觉想说“我倒不会很俗地跳出来说‘好了好了不要吵了’,我觉得看两位的交流也挺能学到东西的”
    mightybruce
        58
    mightybruce  
       26 天前   ❤️ 2
    为什么又菜又爱玩的人希望搞各种没意义的 benchmark, 并且这个人很多语言代码都写不对,
    目前发这些社区唯一还有点意义的是上次那个 1brc 比赛,
    lesismal 是能拿出干货的,比起上面那些只知道搬出社区和框架语言特性的人强出很多, 当然 lesismal 对 go 有偏爱的。
    lesismal
        59
    lesismal  
       26 天前
    @wysnxzm #40 所以,抛开两个话题了的具体内容和前提不谈,拿出两段来进行断章取义的对比,你想表达什么逻辑?
    lesismal
        60
    lesismal  
       26 天前
    @xiaocaiji111

    > 不想跟你对线

    是没必要对线

    > 建议去大公司体验下,看一个系统除了 curd 以外到底有多少其他技术

    这个不用你建议,我就是大公司出身,也是大项目经验,否则我就不搞什么百万连接的解决方案了
    我的主要工作不是 curd ,所以看到很多人只用 curd 的角度格局聊技术,不考虑整体工程,也是挺着急的

    > 或者去看看 JCP 每次的提案有多少新技术,另外我不评价哪个语言好,哪个语言坏,谁工作中只会只用一门语言的。每个场景都有自己最优的选择。

    我也从来没说过 golang 天下第一,我是 c cpp 写的最多,后来 c# node java lua as py 也是项目或者自己玩具一顿用,ruby php 之类的也是稍微玩过,直到用 go 以后就迈不开腿了,不想换其他的语言了。不想换其他语言也不是因为 go 天下第一,而是因为 go 的性能、占用、开发效率、工程性等各方面的平衡

    > 只是看不惯上来就无脑说别人拉踩的,反而显得自己是个小丑。

    我认为 blog 作者的结论是拉踩,如果你认为不是那就认为不是呗。
    如果我认为别人拉踩我就是小丑,那认为”我拉踩我就是小丑“的你也差不多是个小丑吧?没必要这样子
    kneo
        61
    kneo  
       26 天前
    @mightybruce lesismal 拿出了啥干货吗?你别搞笑了。

    他自己的测试结果?那是一个东西吗?那只证明了他搞不清楚原文的并发任务和他自己的并发连接的区别。

    time.AfterFunc()?那是一个东西吗,这会减少 goroutine 数量,也就是减少了并发任务。拼了命减少 goroutine 不就是想说 go goroutine 太多了不行?

    减少协程数能增加性能这叫干货?啊? Java 用了几十年线程池用他教? Java 现在说可以不用线程池了,他开始把自己祖传的协程池拿出来给别人上课。笑死了。

    张嘴闭嘴就自己有干货,回头一看都是啥啊,除了搅乱评论,还真是毫无意义。

    从数据中阅读信息是程序员的基本能力。但凡你们有点能力也不至于得出“毫无意义的测试”这种话来。
    kneo
        62
    kneo  
       26 天前
    @kneo 更正下,goroutine 不是协程。被 lesismal 给拐歪了。
    mightybruce
        63
    mightybruce  
       26 天前
    @kneo 不好意思,time.sleep 是什么,这叫并发任务? 你这么大聪明,建议相互屏蔽。
    kneo
        64
    kneo  
       26 天前
    @mightybruce lesismal 拿出 time.AfterFunc()的时候来我看你也没不好意思啊,跟他上课去吧。
    lesismal
        65
    lesismal  
       26 天前
    @kneo #31

    > 您还自己 at 上来。

    我这个人不阴阳,有事就光明正大地聊,所以直接 at 你了

    > 看您一个劲儿贴自己的库,想骗 star 是吧。

    你是我用户吗?如果不是,你怎么知道我是骗 star 呢?
    有实际用户在生产中使用,或便利,或提升,用户 issue 我都尽量详细回复,bug 我都努力修复,如果这都算骗 star ,那我没法跟你争论,因为你的水准实在太“高”了

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

    这个涉及知识点,我继续认真给你聊.
    不同语言的线程池/协程池/任务队列的排队是不一样的。

    以 4c8g 的规格为例。

    比如传统方式的 c/c++,100 个逻辑线程池 worker (或者多进程)+队列的方式,你的并发只有 100 ,如果任务里 io 或者 sleep 之类的,单个线程就被占用了,如果这组逻辑线程池全都执行这样的任务,就全同时都长时间阻塞了,cpu 不能得到充分有效利用。
    因为 8 或者 100 这个并发度太低了,但是进程或者线程的成本太高了,普通配置的节点没法创建过多的进程或者线程。
    所以这种传统方案要想高性能就得回调的方式。c/c++的协程库也有不少,但需要手动,代码比 go func 更复杂罢了

    但是 go 协程的成本低,4c8g 这种 1-10w 个协程,runtime 也是 ok 的,调度和内存压力都不算大。这个并发度就可以是 10w 。
    实际业务中,从上游到下游本身也会有访问限制,类似“限流”的机制,比如下游的数据库,上游如果 10w 并发都同时去请求数据库,数据库也受不了,所以数据库的使用通常都是长连接+连接池,连接池 size 有限,即使上游调用 sql 并发量吵了也要等空闲连接,而不是直接都丢给数据库把数据库干死
    但 10w 并发本身并发度足够高,即使部分协程等待 sql 连接阻塞了出让 cpu 了,但并不是把线程阻塞了,runtime 会调度其他协程,不会让 cpu 干等着
    然后业务上的协程池和下游资源动态平衡
    具体需要多少并发度需要多大连接池 size 或者其他下游资源的类似”限流“配置,要自己项目实际情况来定,这里的 1-10w 只是举例子


    > 说句不好听的,您连别人测的是啥都看不懂。

    你看懂了?你觉得他这个 benchmark 很有意义?那我对你的自信表示万分钦佩。。。

    > 人家的百万并行任务和你的百万连接是一个东西吗。但是不影响你有个什么破库,在那 BB 好像自己懂似的。在那一顿输出自己的“真才实学”,一边喷人“毫无意义”,

    我说这俩一样了吗?但是 benchmark 是用来干嘛的?是用来为实际工程做参考的,联系实际业务场景扩展相关内容,不行吗?
    分享自己的库的问题,我在 #34 结尾说了
    我是在给开源社区做回报,给我的库的用户带来价值,你认为破还是不破是你的主观是你的自由,但不代表别人,所以我也根本不 care 你
    lesismal
        66
    lesismal  
       26 天前   ❤️ 1
    @kneo #64

    > lesismal 拿出 time.AfterFunc()的时候来我看你也没不好意思啊,跟他上课去吧。

    有什么不好意思的,比如 node 的测试代码,本质上就是定时器回调;
    rust 和 py 的代码本质上应该也是类似的,如果不是类似、而是真的用 sleep ,那这个测试 rust 要跑很久了;

    然后 go 这就不让用定时器回调、必须要用大量有栈协程是吧? time.AfterFunc 到时间了也是起个协程来执行的,但是是用的时候才起来,定时的功能没必要在到时之前就创建大量的协程去等待、白白浪费资源

    非要用这种代码做这种测试,你还要赞同他的测试,如果所有业务都像你这么搞,那你们老板也是挺舍得花冤枉钱的啊


    java 的 VirtualThreads 我不了解别后机制不乱说,另外就是,上下游的各种基础设施,比如请求 sql 是否也是 jvm 支持了出让 cpu 之类的,会不会导致线程阻塞的问题
    这些需要上下游全套 io 相关之类的都避免线程阻塞才有更大意义,否则一个链条线程卡住了,就导致大量排队等待、cpu 利用不起来、性能起不来了
    有哪位懂的可以讲解下让我顺便学习下
    kneo
        67
    kneo  
       26 天前
    @lesismal

    数据你不会看是吗?都画成图了你也看不懂是吗?

    你一口一个 go 协程( goroutine 不是协程),说 goroutine 成本低,原帖的结论之一是 Java 的 virtual thread 比 go 的 goroutine 成本还要低。用最简单的代码,得出最简单的结论。

    我也不需要说测试结果仅供参考之类的。我可以告诉你,这就是结论。请问你拿什么反驳?你在这显摆你那破库?你那破库证明了 goroutine 比 virtual thread 的成本低了吗?

    你那破库顶多能说明,生产环境里,哪怕 goroutine 比 java 的 virtual thread 成本高,也一样能实现高性能应用。当然能啊,Java 没有 virtual thread 不也主宰行业二十年?你拿出来的玩意,对这个讨论一点帮助都没有。除了自我营销和认知水平有限之外,我想不出来你在这捣乱的理由。

    你这种水平的作者,写的库我不也 care ,但是得放在心里,避个雷。我刚才说看了一眼是逗你玩的。你这种库我看名字就知道干啥的。你还真以为帮你贡献点击量了?
    mayli
        68
    mayli  
       26 天前
    C# 的 NativeAOT 真的屌
    Python 没有特别拉跨倒是出乎意料
    lesismal
        69
    lesismal  
       26 天前
    @kneo #67

    > 数据你不会看是吗?都画成图了你也看不懂是吗?

    和着我们说的你都不看是吧?前提和方法错了,还需要看他的测试数据?走错方向了然后说走了很长距离所以虽然方向错了但是很正确很牛逼?

    > 你一口一个 go 协程( goroutine 不是协程)

    这里用的是生产实践约定俗成的概念为准,你不用咬理论概念,你当这写论文呢? go 社区很多人把 goroutine 叫协程是约定俗成的事情,较这个真有意思?
    另外看了眼 wiki 里支持协程的语言列表里也有 go ,你要是非拿着早期一些老爷子的协程概念说事,我建议你把每个语言的协程定义都规范下然后去找各个语言社区推广下看看有没有人乐意花时间跟你咬文嚼字

    > 说 goroutine 成本低,原帖的结论之一是 Java 的 virtual thread 比 go 的 goroutine 成本还要低。用最简单的代码,得出最简单的结论。

    我说 goroutine 成本低是对比进程线程,我说 goroutine 比 java birtual thread 成本低了吗?你这咋还断章取义移花接木呢?
    我说的是他这个测试没意义,结论里虽然没明说,但却是相当于拉踩
    原来你就喜欢没意义的测试结论是吧?那你去给作者点赞吧,这种拉屎的 blog ,我是欣赏不来
    kneo
        70
    kneo  
       26 天前   ❤️ 1
    @lesismal #66 差点被你逗笑了。因为语言的底层实现不一样,所以你就抱怨不公平?还真是委屈你家的 Go 了……咱们以后不比了。
    kneo
        71
    kneo  
       26 天前
    @lesismal #69

    管 goroutine 叫协程是你的叫法,我们社区不这么叫,别给我们抹黑。叫错了就是叫错了,非在这嘴硬?能不能实事求是点?

    你说“看了眼 wiki 里支持协程的语言列表里也有 go”,我也去看了下,

    https://en.wikipedia.org/wiki/Coroutine#Go

    However, goroutines are not coroutines (for instance, local data does not persist between successive calls).

    怀疑你有没有点基本的信息检索能力。怪不得看不懂别人的测试结果。

    嘴硬+阅读能力差,您这 buff 叠满了。
    CloveAndCurrant
        72
    CloveAndCurrant  
       26 天前   ❤️ 1
    @kneo 叫协程也没啥错,所谓 goroutine 就是有栈协程,协程本身就包括有栈和无栈的。叫 goroutine 就是为了区分一下吧
    Kauruus
        73
    Kauruus  
       26 天前   ❤️ 1
    所以一个 goroutine 大约用 (2641592 - 3644) / 1000000 = 2.64 KB 内存?应该还有些 timer 的消耗在里面。

    然后 Java virtual thread 是 (1117640 - 46304) / 1000000 = 1.07 KB ?是因为默认的栈更小还是其他原因?
    kneo
        74
    kneo  
       26 天前
    @lesismal

    > 我说 goroutine 成本低是对比进程线程,我说 goroutine 比 java birtual thread 成本低了吗?

    我说你说了吗?

    你在这刷一天,连个结论都说不出来,我现在告诉你“Java 的 virtual thread 比 go 的 goroutine 成本还要低”,我说了,你反驳我下试试?

    你还“对比进程线程”,你和 Java 8 对比啊?人家测的是 JDK 21 。你要是虚心点看看人家帖子还能学点东西。

    说人家“捧 java 踩 go”,你要像人家一样实事求是贴代码贴数据一步步写结论,没人和你杠。你在这瞎喷还夹带私货,顾左右而言他,还说自己“有技术干货”。

    你知道吗,我“实在看不下去了”,我“必须出来澄清下”。
    yuan1028
        75
    yuan1028  
       26 天前   ❤️ 2
    哈哈哈吵的很有意思,但没必要拉踩语言。我也对 java python 为什么比 go 的内存消耗更小比较好奇?
    然后看了文章提到之前的测试,文章下边有评论说的比较清楚: https://pkolaczk.github.io/memory-consumption-of-async/

    With no doubt, pre-allocating a stack for each goroutine gives Go a disadvantage over languages whose concurrency system postpones any thread-local memory allocation until really needed. (Side note: I use "thread" as a synonym for green or virtual threads and goroutines in this particular context.)

    golang 的 goroutine 是预分配固定大小 2kb 的内存,而 java 的虚拟线程不是预分配,而是根据实际需要的大小去分配。

    感觉可以测试函数里,创建一个大的 map ,来占用内存,看看更加真实接近的内存使用(还能看看 VM 语言的 GC 水平)

    又学到新知识了!
    CloveAndCurrant
        76
    CloveAndCurrant  
       26 天前
    @kneo 你从哪个得出“Java 的 virtual thread 比 go 的 goroutine 成本还要低”这个结论的?😒,虽然都是有栈协程,但是两者实现分配内存机制都不一样,成本低不低要看实际应用情况啊,不能一概而论🙂
    ninjashixuan
        77
    ninjashixuan  
       26 天前
    这种赛博斗蛐蛐的测试也能吵起来。
    kneo
        78
    kneo  
       26 天前
    @CloveAndCurrant 有栈没错,但 goroutine 不是协程啊……
    CloveAndCurrant
        79
    CloveAndCurrant  
       26 天前
    @kneo 定义的神😅
    kneo
        80
    kneo  
       26 天前
    @CloveAndCurrant 实际生产环境的性能表现当然会有各种干扰,没有任何单一指标能决定一切,但不意味着我们不去对单一指标进行量化。Benckmark 的作用之一就是去除变量。

    go 和 java 的优劣固然不能一概而论。但“Java 的 virtual thread 比 go 的 goroutine 成本还要低”这点,我认为是结论。
    kneo
        81
    kneo  
       26 天前
    @CloveAndCurrant

    goroutine 不是协程不是我定义的,我前面有 wiki 链接。

    coroutine 的 co 是 cooperative ,goroutine 是 preemptive 。

    哪怕加上“有栈”的定语,它也不是协程。典型的有栈协程应该是 lua 的 coroutine 。
    kneo
        82
    kneo  
       26 天前
    @yuan1028 朋友,你这才是明灯,这才叫“技术干货”。
    palfortime
        83
    palfortime  
       26 天前 via Android
    刚看了一下代码,这个测试的确有点不公平,rust 在 await 的时候才真正跑。rust 应该要用 spawn ,有人改个加 latch 的版本,看看同时都在跑的时候的占用吗?
    sagaxu
        84
    sagaxu  
       26 天前   ❤️ 1
    @lesismal 66#

    However, when code running in a virtual thread calls a blocking I/O operation, the Java runtime suspends the virtual thread until it can be resumed. The OS thread associated with the suspended virtual thread is now free to perform operations for other virtual threads.

    Java 的 virtual thread 就是为了解决传统线程阻塞时不能让出 CPU 资源提出的方案,如果请求 SQL 就卡住线程了,那就不需要在 JVM 层面提供支持了,完全可以像 Kotlin 一样从 lib 层面支持,调用者自己确保不会阻塞。
    CloveAndCurrant
        85
    CloveAndCurrant  
       26 天前
    @kneo 你认为有个毛用😅,不看实际应用看你认为?在工程领域 goroutine 和 Java virtual thread 都叫有栈协程,Wiki 也是人写的,它也不是什么无上真理。
    CloveAndCurrant
        86
    CloveAndCurrant  
       26 天前
    这个测试虽然有问题,但是 Java 和 golang 我觉得符合预期,Java 的有栈协程实现机制在超大并发的确比 golang 有优势,而对于无栈线程,抛开语言本省内存占用,应该都大差不差。
    kneo
        87
    kneo  
       26 天前
    @CloveAndCurrant 你是不是不认识英文 cooperative ?协程的“协”对你也有点理解困难?你一张嘴说“工程领域就叫有栈协程”,你在工程领域算老几?我还有 WIKI ,你除了你认为你还有毛能拿出来的?
    CloveAndCurrant
        88
    CloveAndCurrant  
       26 天前
    @kneo 怪不得你那么信 Wiki ,自己编的自己信是吧😂,你算老几啊,我说听他是 active ,他就叫活程是吧🤣。我可没说“我认为”,你这个”我认为“怪还倒打一耙了?😂😂😂
    Flourite
        89
    Flourite  
       26 天前
    @grzhan 看了源代码,没有用 sync.Pool ,频繁的开 goroutine ,所以内存占用会比较高,这个测试没有意义

    如果真的在乎 java 跟 go 的差距,还不如看 anton putra 的
    CloveAndCurrant
        90
    CloveAndCurrant  
       26 天前   ❤️ 1
    @kneo 自己抠字眼,扣的要死,协程这个概念早就超出了当时 cooperative 这个范围了,你还那 Wiki 当工程了,那么死板守旧,回去当老古董不是更好😆😆😆
    kneo
        91
    kneo  
       26 天前
    @CloveAndCurrant 啥也拿不出来在这嘴硬,别误人子弟了。

    你知不知道有些错了一辈子的老油条,从一开始就错了,还一直觉得自己是对的,遇到别人振振有词“我们就这么叫”。

    我再重复一遍:Goroutine 不是协程。

    这句不是写给你看的,因为你老了,改不了了。但总有年轻的有心的。他们会知道你是错的。
    thevita
        92
    thevita  
       26 天前
    这么多 coroutine 的实现, 大概分两类

    1. java, golang 有栈实现
    2. 其他 无栈实现

    要比确实也是 java, golang 单独比合适点

    golang 目前版本 使用 initialize size (__StackMin) 为 2k 的 continous stack 作为 coroutine stack

    java virtual thread 不太熟,看了点资料,说是 segmented stack ,从表现来看,应该是更灵活粒度更小的
    grzhan
        93
    grzhan  
       26 天前
    @Flourite 嗯嗯,我觉得其实不少点在后续诸位老板的讨论输出的知识内容里已经比较清晰了(虽然有不少价值判断与情绪输出 hhh ),这样读到的人在了解之后对于这些编程语言都会有自己恰当的判断。
    lesismal
        94
    lesismal  
       26 天前
    @kneo 关于 go 协程这个叫法:
    中文英文这些都有很多方言和约定俗成,在非学术环境,尤其是非严谨学术定义讨论的环境,你非要咬学术概念,那我只能认为你是杠精了。随便搜下 go 协程,只要不瞎你应该可以看到大量的标题文章和内容都是这么叫,一些 go 书籍里也是这么叫。如果你觉得这不算社区约定俗成,那请问你 goroutine 中文你给赐个什么名字?或者 goroutime 必须英文不配中文翻译?或者你自己所在的社区不是 go 社区, 至少不包括 go 的中文社区?
    别觉得自己知道严格的理论概念就可以拿来咬文嚼字了,这种讨论环境下叫协程大家都知道说的是 goroutine, 就你在那为了杠而杠罢了.
    其他一些概念, 例如 tcp 粘包, 我们也知道是错误的定义因为 tcp 本来就是 stream 就不是包, 包是 tcp 之上的层自己的事情, 但是我们讨论问题还是会经常用粘包来描述问题, 因为大家关注的核心点在于这个问题本身而不是这个叫法.
    做工程的纠结这些很容易陷入孔乙己思维,茴字写法精通,做工程耽误事挖坑。我见过不少 cpper 对语言语义标准深入学习, 一聊起这些来, 头头是道,但不擅长踏踏实实搞工程实践,眼高手低。
    我是搞工程实践的,讲究实践主义实用主义,不是搞咬文嚼字的,没那闲心跟学生在那讨论课本考试题概念定义, 你喜欢的话你继续咬文嚼字好了。
    lesismal
        95
    lesismal  
       26 天前   ❤️ 1
    @kneo
    > 你在这刷一天,连个结论都说不出来,我现在告诉你“Java 的 virtual thread 比 go 的 goroutine 成本还要低”,我说了,你反驳我下试试?

    说到这个 blog 的结论,我建议你先看看 blog 的标题吧:
    How Much Memory Do You Need to Run 1 Million Concurrent Tasks ?

    这是测试百万并发任务占用多少内存,而不是百万 go 协程/java 虚拟线程情况下协程和虚拟线程的占用对比,而他的结论呢?
    有的语言是说总占用,go 和 java 又谈协程和虚拟线程了,并且得到的结论之一就是你咬住的这个 “Java 的 virtual thread 比 go 的 goroutine 成本还要低”,我说他文不对题不为过吧?
    如果是为了这种结论,我建议他把标题直接改成 “Java virtual thread vs goroutine memory cost“。

    咱们再回到这个测试的意义上,为什么我说他这个测试没有意义:
    1. 百万并发任务的实现有多种方案,通常是为了测出语言能力的上限,对应内存占用,应该是尽量找出消耗更小的实现,而这个测试里的 go 方案就是用最浪费内存的方式
    2. 例如 node 这种,本质上就是定时器+回调,java 和 go 是有栈 vthread 和 goroutine ,但不论是 java 还是 go ,也都可以用定时器+线程/协程池的方式去实现,这些不同的实现方案来对比内存占用,不只是对 go 不公平,对 java 也是不公平的
    3. blog 作者不同语言采用不公平的方案来测试百万任务,得出虚拟线程和 go 协程占用的对比结论

    综上,在多种语言能够对齐实现方案的前提下,为不同语言采用了内存消耗差异巨大的不同方案,然后为了测试一个目的 A ,得出了一些 XYZ 结论。
    从标题立意,到过程方法,到结论,驴唇不对马嘴!
    说他没意义一点也不为过!

    我刷一天得不得出结论不需要你下结论,但是如果前面你说的这些就是你的结论,我建议你,既然聊技术,即使带着情绪,至少也要对技术的部分心平气和点,多用事实说话而不是只输出语气
    lesismal
        96
    lesismal  
       26 天前
    @kneo 再说说我为什么提到 nbio

    我在 #6 就说过了:

    1. 实际场景里也不可能全是 cpu 消耗的 task, 所以 sleep 类型的 task 是合理的
    3. 如果 sleep 是为了模拟实际场景里的 io 消耗例如网络 io ...

    因为测试是用于给实践作参考,所以看到这些 benchmark 我都会联系实际场景,我看他这个 blog ,会从多方面多个角度去考虑问题,例如前面楼层我讲到的一些,而不是像你那样只看他几个简单文不对题的结论。
    #6 里我也给出了前提,基于实践场景的考虑,并且我也从来没觉得 golang 天下第一,因为我知道 golang 的性能不是第一,也知道海量 goroutine 内存占用带来很大压力、不只是内存,还有 gc 和对应的 stw 。
    所以我把解决方案带出来,但是巧了,这个方案就是我自己搞的,你可以说我是夹带私货,因为确实是夹带私货,但也正如我前面所说,我把好东西拿出来分享,没什么觉得羞愧的,反倒是觉得光荣,因为我确实给有需要的人带来了帮助。

    另外,你说我说的这些技术点不是干货,如果对于你确实不是干货,
    首先我为你感到欣慰,因为这说明你基础知识比较好、已经算是基础很不错的同行了,
    其次我也为你感到惋惜,因为即便掌握了这么多干货知识:
    却不能上来就聊技术的点而是上来就阴阳,
    却只是看到别人个 blog 就跟着人云亦云,
    却不懂得辩证低综合地实践地去分析和看待技术问题,
    却像孔乙己对待茴字一样在这咬文嚼字拿着一个协程概念当成宝,连什么是约定俗成都搞不明白
    。。。
    kneo
        97
    kneo  
       26 天前   ❤️ 1
    @lesismal

    > 说到这个 blog 的结论,我建议你先看看 blog 的标题吧:
    > How Much Memory Do You Need to Run 1 Million Concurrent Tasks ?

    您可下找到重点了。看标题,人家测的就是 Memory ,很明显测一百万是为了知道每个 goroutine (以及其他语言里常见的并发模式)的平均开销。这是这个测试的唯一目的。这个测试结果,不代表 Java 比 Go 强,也不代表 Java 在高性能的表现比 Go 强,连 latency 和 cpu 这种数据都没有,这个测试就是很单纯的一个内存测试,它并不是一个完整的性能测试,但它绝非无效测试。

    具体来说,它提供了一个对比数据:一个 goroutine 的内存开销大概是 2KB ,Java virtual thread 大概是 1KB 。

    这个测试就是这么简单纯粹,没有一点问题。后面也有人提出了“golang 的 goroutine 是预分配固定大小 2kb 的内存”,和测试完全相符。

    您:

    > 毫无意义的测试, 却顺便拉踩, 捧 java 踩 go, 实在看不下去了我才必须出来澄清下.

    遇到质疑,您的回复是:

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

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

    还“半吊子脑残老外”这种话,您也说得出口?礼貌吗?看你现在说话收敛了点,冷静了?自己回头看自己的回复脸红不?

    > 就是你们这种人多了, 才把技术讨论搞得乌烟瘴气!

    信不信,如果你不出现,这个贴子早就在讨论为什么“一个 goroutine 的内存开销大概是 2KB”。

    看你最后几个回帖码字不少,虽然观点我不敢苟同,但能看到到你的微妙变化。不再一一针锋回复了。
    povsister
        98
    povsister  
       26 天前
    哇,这帖子也能吵起来。。
    一个不专业的测试就不专业呗,你能怎么办?

    好为人师的后果:你这人好生无礼。谁叫你多管闲事?
    lesismal
        99
    lesismal  
       26 天前
    @kneo #97 和着他测试方法不对齐, 结论文不对题你是一点都不 care 是吧? 就像是, 咱俩要测试 100 米谁跑得快, 我可能跑不过你, 但是让你坐轮椅用手弄轮子向前, 然后我跑赢了说你跑得慢你也觉得合理是吧?
    前提和基础都错了, 还在这聊什么结论? golang 协程占用还用聊吗, 大把的帖子文章说过这个事情好些年了, 这还用专门去测才能得出结论?

    > 遇到质疑,您的回复是

    你不看看为啥我用这种语气是吧? 你在本帖第一句上来是啥方式在回复自己都不记得了是吧?
    “半吊子脑残老外”确实是不友善, 但也被你们阴阳怪气在先气到了, 而且也是说说事实罢了, 能写这么篇看上去清晰但实际上没有意义甚至误导还好几个站去推广他的观点, 说他半吊子脑残也是陈述事实, 而且不只是在这个帖子里说, 我这个人比较直接, 在你 #97 回复之前我就已经在 reddit 上去回复他了, 英文我直接说 Stupid :
    https://www.reddit.com/r/programming/comments/1h2e35m/comment/lzjwidj/

    我也有菜鸡的时候懵逼的时候头昏说错的时候, 发生这种情况别人喷我 sb 等我反应过来我也乖乖承认, 被人说菜说脑残是自己活该, 毕竟误导了别人

    什么收敛什么脸红, 扯淡! 之前大部分回复, 没有太过认真编辑, 因为上班时间草草回复了事, 前面你所谓收敛的几个, 是因为下班回家了在这时间充沛, 所以把几个完整的逻辑理清了给你, 要是收敛我就不去 reddit 回复原作者了, 这种 blog 是属于坑小白的误导人的, 就该有人出来指正, 当然, 没被你们阴阳气到的话我也不至于这么不礼貌

    至于礼貌, 你们个别人上来不说技术具体的点, 上来就阴阳别人, 这样就礼貌了? 这几年, 不只是 v 站, 各种社媒, 阴阳的人都太多了, 是啥好事情吗? 十句话八句不离阴阳, 有的人甚至张嘴必阴阳, 感情阴阳就是礼貌了? 连技术这种摆在桌面上 1 就是 1 2 就是 2 的问题都不敢直接坦坦荡荡聊非要阴阳, 还跟我谈礼貌, 我的礼貌是留给值得的人的
    lesismal
        100
    lesismal  
       26 天前
    @lesismal #99

    > 就像是, 咱俩要测试 100 米谁跑得快, 我可能跑不过你, 但是让你坐轮椅用手弄轮子向前, 然后我跑赢了说你跑得慢你也觉得合理是吧?

    + 因为虽然 [ 咱俩都可以双腿正常跑, 且用轮椅跟我用双腿正常跑两者方法不一样 ], 但是, 结论确实是你用轮椅比我正常跑慢 —— 这个就跟 blog 这个测试是一样的, 那我建议你保持逻辑的严谨和一贯性, 所以以后你就自认你自己跑得慢吧

    @kneo
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1270 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 17:55 · PVG 01:55 · LAX 09:55 · JFK 12:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.