Go 语言并不像其他一些语言(例如 Java 或 C#)那样直接提供一个线程池的概念。相反,Go 使用 goroutines 来实现并发,它是一种比线程更轻量级的并发执行单元。不过,仍然可以实现一个类似线程池的结构,来管理和限制同时运行的 goroutines 的数量。以下是如何在 Go 中实现一个简单的类似线程池的功能的例子:
package main
import (
"fmt"
"sync"
"time"
)
// WorkerPool 结构体定义
type WorkerPool struct {
jobs chan func() // 用于接收任务的通道
maxJobs int // 最大并发任务数
wg sync.WaitGroup // 用于等待所有任务完成
}
// NewWorkerPool 创建一个新的 WorkerPool
func NewWorkerPool(maxJobs int) *WorkerPool {
pool := &WorkerPool{
jobs: make(chan func(), maxJobs),
maxJobs: maxJobs,
}
return pool
}
// Start 开始 WorkerPool 的工作
func (p *WorkerPool) Start() {
for i := 0; i < p.maxJobs; i++ {
go func() {
for job := range p.jobs {
job()
}
}()
}
}
// Submit 提交一个任务到 WorkerPool
func (p *WorkerPool) Submit(job func()) {
p.wg.Add(1)
p.jobs <- func() {
defer p.wg.Done()
job()
}
}
// Wait 等待所有任务完成
func (p *WorkerPool) Wait() {
p.wg.Wait()
close(p.jobs) // 关闭通道,停止接收新的任务
}
func main() {
// 创建一个最大并发数为 3 的工作池
pool := NewWorkerPool(3)
pool.Start()
for i := 0; i < 10; i++ {
i := i // 创建任务变量的本地副本
pool.Submit(func() {
fmt.Printf("Starting job %d\n", i)
time.Sleep(2 * time.Second) // 模拟耗时操作
fmt.Printf("Finished job %d\n", i)
})
}
// 等待所有任务完成
pool.Wait()
fmt.Println("All jobs completed.")
}
在这个例子中,WorkerPool
结构体有一个 jobs
通道用于接收任务,一个 maxJobs
表示最大并发任务数,和一个 sync.WaitGroup
用于等待所有任务完成。Start
方法启动了 maxJobs
数量的 goroutines,每个 goroutine 不断地从 jobs
通道中接收并执行任务。Submit
方法用于提交新的任务到 jobs
通道,同时增加 WaitGroup
的计数。Wait
方法等待所有任务完成后关闭 jobs
通道。
在 main
函数中,创建了一个最大并发数为 3 的 WorkerPool
,提交了 10 个任务,然后调用 Wait
方法等待所有任务完成。
这个简单的 WorkerPool
实现可以控制同时运行的 goroutines 数量,从而类似于其他语言中的线程池概念。当然,根据实际需求,你可以扩展和定制这个 WorkerPool
的实现,例如添加任务的优先级、错误处理、任务结果的收集等功能。