gui*_*ebl 3 parallel-processing optimization go goroutine worker-pool
我正在构建一个 Go 应用程序,它使用 goroutines 的“工作池”,最初我启动池创建许多工作人员。我想知道多核处理器中的最佳工人数量是多少,例如在具有 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)
Run Code Online (Sandbox Code Playgroud)
完整的实现在下
job.NewWorkerPool(maxWorkers) 和 module.Dispatcher.Run(jobQueue)
我使用工作池的用例:我有一个服务,它接受请求并调用多个外部 API,并将它们的结果聚合到一个响应中。每个调用都可以独立于其他调用,因为结果的顺序无关紧要。我将调用分派到工作池,其中每个调用都以异步方式在一个可用的 goroutine 中完成。一旦工作线程完成,我的“请求”线程就会在获取和聚合结果的同时继续监听返回通道。完成所有操作后,最终聚合结果将作为响应返回。由于每个外部 API 调用可能呈现可变响应时间,因此某些调用可以比其他调用更早完成。
您的示例代码中的注释表明您可能将GOMAXPROCS和 工作池的两个概念混为一谈。这两个概念在 Go 中是完全不同的。
GOMAXPROCS设置 Go 运行时将使用的最大 CPU 线程数。这默认为在系统上找到的 CPU 内核数,并且几乎不应该更改。我能想到的唯一一次改变是,如果您出于某种原因想明确限制 Go 程序使用少于可用 CPU 的数量,那么您可以将其设置为 1,例如,即使在 4-核心 CPU。这应该只在极少数情况下重要。
TL; 博士; 切勿runtime.GOMAXPROCS手动设置。
Go 中的工作池是一组 goroutine,它们在作业到达时对其进行处理。在 Go 中有多种处理工作池的方法。
您应该使用多少工人?没有客观的答案。可能唯一知道的方法是对各种配置进行基准测试,直到找到满足您要求的配置。
作为一个简单的例子,假设您的工作池正在做一些非常占用 CPU 的事情。在这种情况下,您可能需要每个 CPU 一个工人。
不过,作为一个更可能的例子,假设您的工作人员正在做一些 I/O 限制更大的事情——例如读取 HTTP 请求,或通过 SMTP 发送电子邮件。在这种情况下,您可以合理地为每个 CPU 处理数十甚至数千个工人。
还有一个问题是你是否应该使用工作池。Go 中的大多数问题根本不需要工作池。我曾参与过数十个 Go 生产程序,但从未在其中任何一个中使用过工作池。我还多次编写了一次性使用的 Go 工具,并且可能只使用了一次工作池。
最后,GOMAXPROCS和 工作池关联的唯一方式与 goroutines 关联的方式相同GOMAXPROCS。从文档:
GOMAXPROCS 变量限制了可以同时执行用户级 Go 代码的操作系统线程的数量。代表Go代码在系统调用中可以阻塞的线程数没有限制;这些不计入 GOMAXPROCS 限制。这个包的 GOMAXPROCS 函数查询和更改限制。
从这个简单的描述中,很容易看出可能有更多(可能是数十万……或更多)goroutines 比GOMAXPROCS-GOMAXPROCS仅限制“可以同时执行用户级 Go 代码的操作系统线程”的数量 -目前不执行用户级 Go 代码的 goroutine 不算在内。并且在 I/O 绑定的 goroutines 中(例如那些等待网络响应的)不执行代码。因此,理论上的最大协程数仅受系统可用内存的限制。
| 归档时间: |
|
| 查看次数: |
3650 次 |
| 最近记录: |