首页 > 解决方案 > Go 是否提供与 Threadpool 等效的功能

问题描述

我来自 Java/Scala,最近开始使用 Go。在 Java/Scala 中,线程池非常普遍,它们至少有 4 个不同的原因被使用。

  1. 重用工人已经实例化
  2. 资源管理。当我们有多个线程池时,我们可以确保如果系统的某个部分发生突发事件,它不会阻止其他部分运行。
  3. 自定义我们想要的调度类型(fork/join、classic、scheduled 等......)
  4. 自定义拒绝策略。

由于 Goroutine 很轻1是不需要的,即使提供一个也很好,我们可以创建某种工作池,而不需要太多麻烦来解决2

但是,我觉得在 Go 中我们无法处理34

是因为不需要它还是只是缺少功能?

标签: goconcurrencythreadpoolgoroutine

解决方案


正如您所猜到的,由于 (1) 在 Go 中基本上不是问题,因此对线程/工作池的需求要少得多。(2) 也可以使用速率限制和资源信号量等技术来解决。至于 (3),Go 运行时会执行 goroutine 调度,因此自定义它并不容易,也不是惯用的。

也就是说,线程/工作池在 Go 中非常容易实现。这是gobyexample的一个简单示例:

// In this example we'll look at how to implement
// a _worker pool_ using goroutines and channels.

package main

import "fmt"
import "time"

// Here's the worker, of which we'll run several
// concurrent instances. These workers will receive
// work on the `jobs` channel and send the corresponding
// results on `results`. We'll sleep a second per job to
// simulate an expensive task.
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        results <- j * 2
    }
}

func main() {

    // In order to use our pool of workers we need to send
    // them work and collect their results. We make 2
    // channels for this.
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    // This starts up 3 workers, initially blocked
    // because there are no jobs yet.
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Here we send 5 `jobs` and then `close` that
    // channel to indicate that's all the work we have.
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)

    // Finally we collect all the results of the work.
    // This also ensures that the worker goroutines have
    // finished. An alternative way to wait for multiple
    // goroutines is to use a [WaitGroup](waitgroups).
    for a := 1; a <= 5; a++ {
        <-results
    }
}

如果你谷歌一下,你会发现一堆 3rd-party 包为各种用途实现了这种模式。正如您可能猜到的那样,没有单一的最佳方法可以做到这一点,因此您将选择对您的特定用例重要的任何方法。


推荐阅读