什么??go中的协程池竟然.........

什么是协程池

协程池简单理解就是有一个池子一样的东西,里面装这个固定数量的goroutine,当有一个任务到来的时候,会将这个任务交给池子里的一个空闲的goroutine去处理,如果池子里没有空闲的goroutine了,任务就会阻塞等待。

如何构建协程池

首先定义一个协程池的结构体

go 复制代码
type WorkerPool struct {
    Jobs    chan func()//公共的通道,到时候任务写进这里面
    MaxWorkers int//设置协程池最多有多少个协程
}

然后创建一个协程

go 复制代码
func NewWorkerPool(maxWorkers int) *WorkerPool {
    pool := &WorkerPool{
        Jobs:       make(chan func()),//初始化
        MaxWorkers: maxWorkers,
    }
    for i := 0; i < pool.MaxWorkers; i++ {
        go pool.worker()//这里就是创建多个协程
    }
    return pool
}
go 复制代码
func (p *WorkerPool) worker() {
    for job := range p.Jobs {//这里就是从公共通道里面获取任务
        job()
    }
}

以上,最简单的协程池就算创建好了。

协程池的使用

go 复制代码
func (p *WorkerPool) AddJob(job func()) {
    p.Jobs <- job
}

这里就是将任务函数传进通道里,然后公平地分给各个空闲的协程。

协程池的关闭

go 复制代码
func (p *WorkerPool) Close() { 
     close(p.Jobs) 
}

完整健壮的协程池

go 复制代码
type WorkerPool struct {
    Jobs         chan func()
    MaxWorkers   int
    wg           sync.WaitGroup // 新增:任务完成计数器
}

func NewWorkerPool(maxWorkers int) *WorkerPool {
    pool := &WorkerPool{
        Jobs:       make(chan func()),//初始化
        MaxWorkers: maxWorkers,
    }
    for i := 0; i < pool.MaxWorkers; i++ {
        go pool.worker()//这里就是创建多个协程
    }
    return pool
}

func (p *WorkerPool) worker() {
    
    for job := range p.Jobs {//这里就是从公共通道里面获取任务
        defer func() {
                if r := recover(); r != nil {
                    log.Printf("Worker panic: %v", r)
                 }
         }()
         
         job()
         
     }
}

func (p *WorkerPool) AddJob(job func()) {
	p.wg.Add(1) // 任务数+1
	p.Jobs <- func() {        //这里的func匿名函数就是上面的job处理函数
            defer p.wg.Done()
            job()              // 执行实际任务
	}
}

func (p *WorkerPool) Wait() {
	p.wg.Wait() // 阻塞直到所有任务完成
}

func main() {
	pool := NewWorkerPool(2)

	// 添加 3 个任务
	pool.AddJob(func() { time.Sleep(1 * time.Second) })
	pool.AddJob(func() { time.Sleep(1 * time.Second) })
	pool.AddJob(func() { time.Sleep(1 * time.Second) })

	// 主协程等待任务完成
	defer fmt.Println("主协程结束")
	pool.Wait() // **关键:阻塞在这里直到所有任务完成**
}

上面的代码添加了

go 复制代码
sync.WaitGroup

defer func() {
    if r := recover(); r != nil {
        log.Printf("Worker panic: %v", r) 
        } 
 }()

第一个用来确保在channel中的时间完全完成之后才可以结束文件。

第二个用来确保在每个任务出现问题时不会影响整个协程池的正常运行

相关推荐
爷_12 小时前
Golang: sqlc 和 goose 最佳实践
后端·go·全栈
万少13 小时前
我是如何使用 Trae IDE 完成《流碧卡片》项目的完整记录
前端·后端·ai编程
ituff13 小时前
微软认证考试又免费了
后端·python·flask
倔强的石头_13 小时前
openGauss赋能智能客服:AI时代的企业服务变革
后端
自不量力的A同学14 小时前
Spring Boot 4.0.0 正式发布
java·spring boot·后端
d***292414 小时前
【spring】Spring事件监听器ApplicationListener的使用与源码分析
java·后端·spring
v***56515 小时前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
码事漫谈15 小时前
C++中不同类型的默认转换详解
后端
码事漫谈15 小时前
C++类型转换的隐蔽陷阱:当size_t遇见负数
后端