什么??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中的时间完全完成之后才可以结束文件。

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

相关推荐
jakeswang4 小时前
去哪儿StarRocks实践
starrocks·后端
字节逆旅5 小时前
从一次爬坑看前端的出路
前端·后端·程序员
Chan166 小时前
【智能协同云图库】第七期:基于AI调用阿里云百炼大模型,实现AI图片编辑功能
java·人工智能·spring boot·后端·spring·ai·ai作画
mitt_6 小时前
go语言变量
开发语言·后端·golang
无限大67 小时前
二维数组搜索:从暴力地毯到二分神技的奇幻之旅
后端
bobz9657 小时前
最近玩了好多把 LOL
后端
爱欲无极8 小时前
基于Flask的微博话题多标签情感分析系统设计
后端·python·flask
cwkiller8 小时前
heapdump深度利用之信息泄露篇
后端
Olrookie10 小时前
若依前后端分离版学习笔记(五)——Spring Boot简介与Spring Security
笔记·后端·学习·spring·ruoyi
小白的代码日记10 小时前
基于 Spring Boot 的小区人脸识别与出入记录管理系统实现
java·spring boot·后端