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

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

相关推荐
80530单词突击赢1 小时前
JavaWeb进阶:SpringBoot核心与Bean管理
java·spring boot·后端
爬山算法2 小时前
Hibernate(87)如何在安全测试中使用Hibernate?
java·后端·hibernate
WeiXiao_Hyy2 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
苏渡苇2 小时前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
long3162 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
rannn_1113 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
短剑重铸之日3 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
Dragon Wu4 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
一个有梦有戏的人4 小时前
Python3基础:进阶基础,筑牢编程底层能力
后端·python
爬山算法5 小时前
Hibernate(88)如何在负载测试中使用Hibernate?
java·后端·hibernate