工人池Golang的最佳规模

问题描述 投票:0回答:1

我正在构建一个使用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

go optimization parallel-processing goroutine worker-pool
1个回答
3
投票

示例代码中的注释表明您可能会混淆GOMAXPROCS和工作池这两个概念。这两个概念在Go中完全不同。

  1. GOMAXPROCS设置Go运行时将使用的最大CPU线程数。默认为系统上找到的CPU核心数,几乎不应更改。我唯一能想到改变这种情况的方法是,如果你想明确限制Go程序因某些原因使用少于可用的CPU,那么你可以将它设置为1,例如,即使在4上运行核心CPU。这应该只在极少数情况下才有意义。 TL; DR;切勿手动设置runtime.GOMAXPROCS
  2. Go中的工作池是一组goroutines,它们在到达时处理作业。 Go中有不同的处理工作池的方法。 你应该使用多少工人?没有客观的答案。可能唯一的方法就是对各种配置进行基准测试,直到找到符合要求的配置。 作为一个简单的例子,假设您的工作池正在执行非常占用CPU的事情。在这种情况下,您可能需要每个CPU一个工作线程。 但是,作为一个更可能的例子,假设您的工作人员正在执行更多I / O限制 - 例如读取HTTP请求或通过SMTP发送电子邮件。在这种情况下,您可以合理地处理每个CPU数十甚至数千个工作者。 然后还有一个问题,即你是否应该使用工作池。 Go中的大多数问题根本不需要工作池。我已经研究过几十个生产Go程序,从来没有在其中任何一个中使用过工作池。我还写过多次一次性使用Go工具,并且只使用一次工作池。

最后,GOMAXPROCS和工人池相关的唯一方式与goroutines与GOMAXPROCS的关系相同。来自the docs

GOMAXPROCS变量限制了可以同时执行用户级Go代码的操作系统线程数。代表Go代码在系统调用中可以阻塞的线程数没有限制;那些不计入GOMAXPROCS限制。该软件包的GOMAXPROCS函数查询并更改限制。

从这个简单的描述中,很容易看出可能有更多(可能是数十万......或更多)goroutine比GOMAXPROCS - GOMAXPROCS只限制了多少“可以同时执行用户级Go代码的操作系统线程” - 目前没有执行用户级Go代码的--goroutines不计算在内。在I / O绑定的goroutine(例如等待网络响应的那些)中没有执行代码。因此,理论上最大数量的goroutine仅受系统可用内存的限制。

© www.soinside.com 2019 - 2024. All rights reserved.