Go: 使用GODEBUG改善Goroutine的使用

goroutine轻量的特点往往被认为是改善程序的解决方案。不幸的是,由于goroutine上下文切换消耗,goroutine的不当使用反而会降低程序的性能。

背景&测试

背景:对超过10k的数据文档进行计算

下面给出第一个待测试的算法逻辑

其中每1000个文档启动一个goroutine,基准测试如下

让我们在计算中使用更多的goroutine对每个文档单独goroutine计算。修改如下

基准测试如下:

现在结果慢了11%,但是这是预期之中的,实际上,以上场景是纯数学计算,因此导致go调度器没有机会在新goroutine中发挥作用。

由于上下文切换而导致的Goroutine延迟

我们需要分析go调度器如何运行goroutine。我们首先分析”算法1“。我们将使用GODEBUG运行基准测试。

schedtrace=1 将会打印go调度器每ms的调度事件。这里是一部分trace信息

gomaxprocs 显示可用的处理器数量,idleprocs显示空闲处理器数量, runqueue显示全局队列中等待的goroutine数量,([0 0]) 显示了每个单独处理器本地队列中等待的goroutine数量。

我们可以发现这里goroutine的使用率不高,处理器也不繁忙,我们想知道我们是否需要增加更多的goroutine来利用这些闲置资源。让我们尝试对”算法2“进行相同的分析,并为每个文档使用单独的goroutine来计算。

现在我们可以发现大量goroutine在全局和本地队列中,处理器也处于繁忙状态。但是很快处理器就再次恢复空闲状态。我们可以通过tracer分析goroutine。

                                                                               tracer goroutines 分析

goroutine 209 等待服务器返回

如我们所见,大多数goroutine在批量记录( bulk record)时等待服务器的响应。 这是我们应该集中精力改进并利用这一等待时间的地方。 这就是为什么我们为批量记录文档单独创建goroutines的原因。

我们现在也可以理解在计算中增加goroutine并没有产生收益,因为计算是没有等待的(不同于上面提到的批量记录时存在网络等待),系统无法让当前goroutine暂停来让另一个goroutine运行。

总结

综上在存在io等待的场景可以通过基准测试的方式增加goroutine数量来提升程序性能,纯计算场景建议配合基准测试基于或低于cpu数量来设置goroutine数量以获得最佳性能。

编译整理自  Go: Improve the Usage of Your Goroutines with GODEBUG

张贴在Go标签:

版权声明: 本文为【陈思敏捷】的原创文章。
原文链接:【https://www.chenjie.info/2398】。原文标题:【Go: 使用GODEBUG改善Goroutine的使用】。文章转载请联系作者。

欢迎订阅我的公众号,文章更新早知道


发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据