项目背景
# 1. 项目背景
首先,goroutine 规模化后内存占用比较大
一个 Goroutine 的起始栈大小为 2KB,创建、切换与销毁的代价很低,可以创建成千上万甚至更多 Goroutine。
不过,Goroutine 的开销虽然“廉价”,但规模化后,这种非零成本也会成为瓶颈。以一个 Goroutine 分配 2KB 执行栈为例,100w Goroutine 就是 2GB 的内存消耗。
其次,goroutine 容易造成资源浪费
Goroutine 从Go 1.4 版本开始采用了连续栈的方案,也就是每个 Goroutine 的执行栈都是一块连续内存,如果空间不足,运行时会分配一个更大的连续内存空间作为这个 Goroutine 的执行栈,将原栈内容拷贝到新分配的空间中来。
连续栈的方案,虽然能避免 Go 1.3 采用的分段栈会导致的“hot split”问题,但连续栈的原理也决定了,一旦 Goroutine 的执行栈发生了 grow,那么即便这个 Goroutine 不再需要那么大的栈空间,这个 Goroutine 的栈空间也不会被 Shrink(收缩)了,这些空间可能会处于长时间闲置的状态,直到 Goroutine 退出。
另外,Goroutine 调度会消耗比较大的cpu资源
随着 Goroutine 数量的增加,Go 运行时进行 Goroutine 调度的处理器消耗,也会随之增加,成为阻碍 Go 应用性能提升的重要因素。
常见的解决方案:Goroutine 池(workerpool)。
这个方案的核心思想是对 Goroutine 的重用,也就是把 M 个计算任务调度到 N 个 Goroutine 上,而不是为每个计算任务分配一个独享的 Goroutine,从而提高计算资源的利用率。
上次更新: 2022/06/12, 15:48:09