云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

分布式数据库_云存储多少钱一个月_企业0元试用

小七 141 0

去吧,别收我的垃圾

不久前,我需要在多核机器上测试Golang的性能。我获取了一些与Go源代码捆绑在一起的基准测试,复制它们,并修改它们以在所有可用线程上运行。在这种情况下,机器有24个芯和48个螺纹。CC BY-SA 2.0 sponki25提供的图像我从ECDSA P256 Sign开始,可能是因为我为amd64优化了它,所以对该功能有一种温暖的感觉。首先,我在一个goroutine上运行基准:ECDSA-P256 Sign,30618.50,op/s看起来不错;接下来我在48个goroutines上运行它:ECDSA-P256 Sign,78940.67,op/s。好吧,那不是我所期望的。从24个物理核心加速超过2倍?我一定是做错了什么。也许围棋只使用两个核心?我跑了第一,显示出2266%的利用率。这不是我预期的4800%,但也远高于400%。退一步,在两个goroutine上运行基准测试怎么样?ECDSA-P256标牌,55966.40,开/关。几乎翻了一番,很不错。四次约会怎么样?ECDSA-P256标牌,108731.00,op/s。实际上比48个goroutines快,怎么回事?我为从1到48的goroutine运行了基准测试:看起来每秒的签名数达到了274622个峰值,有17个goroutine。然后开始迅速下降。是时候做些分析了。(pprof)前10名显示节点数为47.53s,占93.50s的50.83%丢弃224个节点(cum4->0MB,5MB目标,48Pgc2@0.024s 0%:0.097+0.94+0.16ms时钟,0.29+0.21/1.3/0+0.49ms cpu,4->4->1MB,5MB目标,48Pgc3@0.027s 1%:0.10+0.43+0.17ms时钟,0.60+0.48/1.5/0+1.0ms cpu,4->4->0MB,5MB目标,48Pgc4@0.028s 1%:0.18+0.41+0.28ms时钟,0.18+0.69/2.0/0+0.28ms cpu,4->4->0MB,5MB目标,48Pgc5@0.031s 1%:0.078+0.35+0.29ms时钟,1.1+0.26/2.0/0+4.4ms cpu,4->4->0MB,5MB目标,48Pgc 6@0.032s 1%:0.11+0.50+0.32毫秒时钟,0.22+0.99/2.3/0+0.64毫秒cpu,4->4->0MB,5 MB目标,48 Pgc 7@0.034s 1%:0.18+0.39+0.27毫秒时钟,0.18+0.56/2.2/0+0.27毫秒cpu,4->4->0MB,5 MB目标,48 Pgc 8@0.035s 2%:0.12+0.40+0.27毫秒时钟,0.12+0.63/2.2/0+0.27毫秒cpu,4->4->0MB,5MB目标,48Pgc 9@0.036s 2%:0.13+0.41+0.26ms时钟,0.13+0.52/2.2/0+0.26ms cpu,4->4->0MB,5MB目标,48Pgc10@0.038s 2%:0.099+0.51+0.20ms时钟,0.19+0.56/1.9/0+0.40ms cpu,4->5->0MB,5MB目标,48Pgc11@0.039s 2%:0.10+0.46+0.20ms时钟,0.10+0.23/1.3/0.005+0.20ms cpu,4->4->0MB,5MB目标,48Pgc 12@0.040s 2%:0.066+0.46+0.24ms时钟,0.93+0.40/1.7/0+3.4ms cpu,4->4->0MB,5MB目标,48Pgc 13@0.041s 2%:0.099+0.30+0.20ms时钟,0.099+0.60/1.7/0+0.20ms cpu,4->4->0MB,5MB目标,48Pgc 14@0.042s 2%:0.095+0.45+0.24毫秒时钟,0.38+0.58/2.0/0+0.98毫秒cpu,4->5->0MB,5 MB目标,48 Pgc15@0.044s 2%:0.095+0.45+0.21ms时钟,1.0+0.78/1.9/0+2.3ms cpu,4->4->0MB,5MB目标,48Pgc 16@0.045s 3%:0.10+0.45+0.23ms时钟,0.10+0.70/2.1/0+0.23ms cpu,4->5->0MB,5MB目标,48Pgc 17@0.046s 3%:0.088+0.40+0.17ms时钟,0.088+0.45/1.9/0+0.17ms cpu,4->4->0MB,5MB目标,48P....gc 6789@9.998s 12%:0.17+0.91+0.24毫秒时钟,0.85+1.8/5.0/0+1.2毫秒cpu,4->6->1MB,6MB目标,48Pgc 6790@10.000s 12%:0.086+0.55+0.24毫秒时钟,0.78+0.30/4.2/0.043+2.2ms cpu,4->5->1MB,6MB目标,48P第一轮GC在0.021s开始,然后每隔3ms开始收集,然后每1ms收集一次,这太疯狂了,基准测试运行了10秒,我看到了6790轮GC。以@。这个数字显然具有误导性,因为性能表明至少90%的时间(间接)浪费在GC上,而不是12%。不考虑同步开销。真正有趣的是用箭头隔开的三个数字。它们显示GC开始、GC结束时的堆大小和活动堆大小。请记住,当新分配的数据与上一次收集后剩余的实时数据的比率达到此百分比时,将触发收集,默认值为100%。我正在运行一个基准测试,在这个基准测试中,所有分配的数据都会被立即丢弃,并在下一个GC周期收集。唯一的活动堆是固定到Go运行时的,拥有更多goroutine不会添加到活动堆中。相比之下,每增加一个goroutine,新分配的数据增长得更快,从而触发越来越频繁且昂贵的GC周期。很明显,我下一步需要做的是在禁用GC的情况下运行基准测试,方法是设置GOGC=off。这导致了一个巨大的改善:ECDSA-P256标志,413740.30,op/s。但仍然不是我要找的数字,从长远来看,运行一个没有垃圾回收的应用程序是不可持续的。我开始玩GOGC变量。首先,我将其设置为2400,这是有意义的,因为我们有24个核心,也许收集垃圾的频率降低24倍就可以做到了:ECDSA-P256 Sign,671538.90,op/s,哦,天哪,这越来越好了。如果我尝试4800个线程呢?ECDSA-P256标牌,685810.90,手术室/室。温度升高。我运行了一个脚本来寻找最佳值,从100到20000,以100为增量。我得到的是:在这种情况下,GOGC的最佳值是11300个,每秒可以得到691054个签名。这个速度是单核处理器的22.56倍,对于一个24核处理器来说,总体来说相当不错。请记住,在单核上运行时,CPU频率为3.0GHz,在所有核心上运行时,CPU频率仅为2.1GHz。使用GOGC=11300运行时的每goroutine性能如下所示:扩展看起来更好,甚至在过去的24个goroutine中,当我们用完物理内核,并开始与超线程共享内核时,整体性能也会提高。这里的底线是,尽管这种类型的基准测试对于垃圾收集来说绝对是一种边缘情况,在这种情况下,48个线程分配大量的短期数据,但这种情况在真实场景中可能会发生。随着许多核心cpu成为商品,人们应该意识到其中的陷阱。大多数具有垃圾收集功能的语言都提供了某种垃圾收集控制。Go有GOGC变量,也可以用runtime/debug包中的SetGCPercent函数来控制它。不要害怕调整GC以满足您的需要。我们一直在寻找围棋程序员,所以如果你觉得这篇博文很有趣,为什么不看看我们的[jobs page](https://www.cloudflare.com/join-our-team)?