Golang 中的协程池(goroutine pool)有哪些实现方式?

在 Golang 中,协程池(goroutine pool)是管理一组可复用 goroutine 的机制。它可以实现限制 goroutine 数量,复用 goroutine 等效果。

goroutine 池常见的实现方式有:

  1. 无大小限制的池:
func worker(jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int)

    for i := 0; i < 10; i++ { // 开启10个goroutine
        go worker(jobs, results)
    }

    for j := 0; j < 100; j++ {
        jobs <- j
    }
    close(jobs)

    for a := 0; a < 100; a++ {
        <-results
    }
}

这里简单地开启 10 个 goroutine,没有限制池大小。

  1. 固定大小的池:
func worker(jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int)
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {  // 限制池大小为10
        wg.Add(1)
        go func() {
            defer wg.Done()
            worker(jobs, results) 
        }()
    }

    for j := 0; j < 100; j++ {
        jobs <- j
    }
    close(jobs)

    wg.Wait()   // 等待所有goroutine结束
    close(results)
}

这里限制池大小为 10,通过 wg.Add(1) 和 wg.Done() 实现计数。

3.带缓冲的池:

func worker(jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {   // 限制池大小为10
        wg.Add(1)
        go func() {
            defer wg.Done()
            worker(jobs, results)  
        }()
    }

    for j := 0; j < 100; j++ {
        jobs <- j
    }
    close(jobs)

    wg.Wait()  // 等待所有goroutine结束 
    close(results)
}

这里给 results 添加了缓冲,可以存放一定数量的结果,避免 goroutine 积压。

所以 goroutine 池的主要作用是:

  1. 限制 goroutine 的数量,避免创建过多 goroutine 导致内存爆炸。
  2. 复用 goroutine,减少创建和销毁 goroutine 的开销。
  3. 在一定程度上实现流量控制,避免 goroutine 洪水。

goroutine 池常用于实现工作线程池、任务队列调度等场景。熟练掌握 goroutine 池的实现方式,可以帮助我们设计出更加高效和稳定的并发程序。

总之,goroutine 池是管理 goroutine 的一种重要机制。合理使用可以充分发挥 goroutine 的优势,同时减少由于大量 goroutine 导致的性能损耗与资源消耗。