假设我有一个像树一样分支的工作负载。
我必须处理
n
A 项目。m
B 项目。我有以下功能:
func handler() {
var aList []A
var wg sync.WaitGroup
for _, a := range aList {
wg.Add(1)
go func () {
defer wg.Done()
processA(a)
}
}
wg.Wait()
}
func processA(a A) error {
var wg sync.WaitGroup
for _, b := range a.BList {
wg.Add(1)
go func () {
defer wg.Done()
processB(b)
}
}
wg.Wait()
}
func processB(b B) error {
var wg sync.WaitGroup
for _, c := range b.CList {
wg.Add(1)
go func () {
defer wg.Done()
processC(c)
}
}
wg.Wait()
}
现在所有这些任务的本质是它们是 BSP(批量同步进程)。
我的意思是,他们之间不需要相互沟通。
更重要的是,如果我有无限数量的核心,那么任何线程/goroutine 中都会有NO等待。
现在让我们回到现实,我正在 Lambda 函数上运行它,该函数将提供 2/3/4 个核心。
我的工作负载仍然如此,不会达到内存限制。
现在我应该更改代码来限制 goroutine 的数量吗?
如果我想要的是加速?
我的代码是否由于上下文切换过多而滞后?
或者说不存在“太多 goroutine”这样的事情吗?
答案并不令人满意:这要看情况。
您需要将分析纳入您的开发周期,以了解最佳的前进方式 - CPU 和跟踪分析非常适合此目的。我们无法轻松预测您的工作量。
更重要的是,如果我有无限数量的核心,那么任何线程/goroutine 中都不会有等待。
如果您说工作完全受 CPU 限制,那么拥有等于 CPU 数量的 goroutine 可能会表现最佳。然后,您的外部逻辑通过通道将工作发送给每个工作人员。
跟踪配置文件将显示每个 CPU 的工作调度效率如何。 CPU 分析可以突出显示热点所在。
Dave Cheney 在一次演讲中展示了三种分析技术,其中一种是过多的 goroutine 会减慢受 CPU 限制的程序的速度。值得一看:https://www.youtube.com/watch?v=nok0aYiGiYA
从技术上讲,在内存耗尽之前,不存在“太多 goroutine”之类的事情,但我认为这并不是您所要求的。在实践中没有一个快速的答案,但有一些有用的信息:
总的来说,我强烈推荐: