我正在构建一个使用goroutines“工作池”的Golang应用程序,最初我开始创建一些工作池。我想知道多核处理器中的最佳工作数是多少,例如在具有4个内核的CPU中?我目前正在使用以下方法:
// init pool
numCPUs := runtime.NumCPU()
runtime.GOMAXPROCS(numCPUs + 1) // numCPUs hot threads + one for async tasks.
maxWorkers := numCPUs * 4
jobQueue := make(chan job.Job)
module := Module{
Dispatcher: job.NewWorkerPool(maxWorkers),
JobQueue: jobQueue,
Router: router,
}
// A buffered channel that we can send work requests on.
module.Dispatcher.Run(jobQueue)
完整的实施是在
job.NewWorkerPool(maxWorkers)和module.Dispatcher.Run(jobQueue)
我使用工作池的用例:我有一个服务接受请求并调用多个外部API并将其结果聚合到一个响应中。每次通话都可以独立完成,因为结果顺序无关紧要。我将调用分派给工作池,每个调用都以异步方式在一个可用的goroutine中完成。我的“请求”线程在工作线程完成后立即获取和聚合结果时继续监听返回通道。完成所有操作后,最终的聚合结果将作为响应返回。由于每个外部API调用可能呈现可变响应时间,因此某些调用可以比其他调用更早完成。根据我的理解,以并行的方式执行它会在性能方面更好,就好像以同步方式一样,一个接一个地调用每个外部API
示例代码中的注释表明您可能会混淆GOMAXPROCS
和工作池这两个概念。这两个概念在Go中完全不同。
GOMAXPROCS
设置Go运行时将使用的最大CPU线程数。默认为系统上找到的CPU核心数,几乎不应更改。我唯一能想到改变这种情况的方法是,如果你想明确限制Go程序因某些原因使用少于可用的CPU,那么你可以将它设置为1,例如,即使在4上运行核心CPU。这应该只在极少数情况下才有意义。
TL; DR;切勿手动设置runtime.GOMAXPROCS
。最后,GOMAXPROCS
和工人池相关的唯一方式与goroutines与GOMAXPROCS
的关系相同。来自the docs:
GOMAXPROCS变量限制了可以同时执行用户级Go代码的操作系统线程数。代表Go代码在系统调用中可以阻塞的线程数没有限制;那些不计入GOMAXPROCS限制。该软件包的GOMAXPROCS函数查询并更改限制。
从这个简单的描述中,很容易看出可能有更多(可能是数十万......或更多)goroutine比GOMAXPROCS
- GOMAXPROCS
只限制了多少“可以同时执行用户级Go代码的操作系统线程” - 目前没有执行用户级Go代码的--goroutines不计算在内。在I / O绑定的goroutine(例如等待网络响应的那些)中没有执行代码。因此,理论上最大数量的goroutine仅受系统可用内存的限制。