golang 协程池 动态扩缩容

参考 github.com/panjf2000/ants

go 复制代码
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	_ "github.com/panjf2000/ants"
)

type pool struct {
	// 协程池最大容量
	cap int32
	// 当前运行的协程个数
	run   int32
	block bool

	// 空闲goroutinue
	idleWorkers []*worker
	// 最大空闲时间,超过就挥手
	idleTimeoutSec uint32

	lock  sync.Mutex
	cond  *sync.Cond
	close chan struct{}
	wg    sync.WaitGroup
}

func NewPool(cap int32) *pool {
	c := &pool{
		cap: cap,
		//idleWorkers: make([]*worker, 0, cap),
		close: make(chan struct{}),
	}
	c.cond = sync.NewCond(&c.lock)
	go c.checkIdleWork()
	return c
}

func (p *pool) checkIdleWork() {
	for {
		select {
		case <-time.After(time.Second * 5):
			{
				p.lock.Lock()
				defer p.lock.Unlock()

				var i = 0
				for ; i < len(p.idleWorkers) &&
					uint32(time.Now().Unix())-p.idleWorkers[i].lastWorkTs >= p.idleTimeoutSec; i++ {
				}

				fmt.Printf("checkIdleWork del=%d\n", i)
				if i > 0 {
					for j := 0; j < i; j++ {
						atomic.AddInt32(&p.run, -1)
						p.idleWorkers[j].task <- nil
					}

					p.idleWorkers = p.idleWorkers[i:]
					fmt.Printf("checkIdleWork now run=%d, del=%d\n", len(p.idleWorkers), i)
				}
			}
		}
	}
}

func (p *pool) Done() {
	p.wg.Done()
}

func (p *pool) Close() {
	fmt.Printf("pool Close\n")
	close(p.close)
	p.wg.Wait()
}

func (p *pool) backPool(w *worker) {
	p.lock.Lock()
	p.idleWorkers = append(p.idleWorkers, w)
	p.lock.Unlock()
	p.cond.Signal()
	fmt.Printf("backPool\n")
}

func (p *pool) Submit(task func()) error {

	p.lock.Lock()
	if len(p.idleWorkers) > 0 {
		work := p.idleWorkers[len(p.idleWorkers)-1]
		p.idleWorkers = p.idleWorkers[:len(p.idleWorkers)-1]
		work.task <- task
		p.lock.Unlock()
		fmt.Printf("use idle\n")
		return nil
	}
	p.lock.Unlock()

	if p.run < p.cap {
		fmt.Printf("use new\n")
		work := &worker{
			pool: p,
			task: make(chan func()),
		}

		p.wg.Add(1)
		work.run()
		atomic.AddInt32(&p.run, 1)

		work.task <- task
		return nil

	} else {

	loop:
		if p.block {
			return fmt.Errorf("pool max")
		}

		fmt.Printf("pool max, wait\n")
		p.lock.Lock()
		p.cond.Wait()

		if len(p.idleWorkers) > 0 {
			work := p.idleWorkers[len(p.idleWorkers)-1]
			p.idleWorkers = p.idleWorkers[:len(p.idleWorkers)-1]
			work.task <- task
			p.lock.Unlock()
			fmt.Printf("use idle\n")
			return nil
		}
		p.lock.Unlock()

		if p.run < p.cap {
			work := &worker{
				pool: p,
				task: make(chan func()),
			}
			p.wg.Add(1)
			work.run()
			atomic.AddInt32(&p.run, 1)
			work.task <- task

			fmt.Printf("use new\n")
			return nil
		}

		goto loop

		return nil
	}
}

type worker struct {
	pool       *pool
	task       chan func()
	lastWorkTs uint32
}

func (w *worker) run() {

	go func() {
		defer w.pool.Done()

		for {
			select {
			case <-w.pool.close:
				return
			case taskFunc := <-w.task:
				if taskFunc == nil {
					return
				}
				taskFunc()
				w.lastWorkTs = uint32(time.Now().Unix())
				w.pool.backPool(w)
			}
		}
	}()
}

func main() {

	p := NewPool(20)

	for i := 0; i < 5; i++ {

		p.Submit(func() {
			func(idx int) {
				fmt.Printf("work %d ..\n", idx)
				time.Sleep(time.Second * 4)
			}(i)
		})

	}

	time.Sleep(time.Second * 10)
	p.Close()
}
相关推荐
coderWangbuer5 分钟前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
无限大.9 分钟前
c语言200例 067
java·c语言·开发语言
余炜yw10 分钟前
【Java序列化器】Java 中常用序列化器的探索与实践
java·开发语言
攸攸太上11 分钟前
JMeter学习
java·后端·学习·jmeter·微服务
篝火悟者12 分钟前
问题-python-运行报错-SyntaxError: Non-UTF-8 code starting with ‘\xd5‘ in file 汉字编码问题
开发语言·python
Kenny.志14 分钟前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
Death20014 分钟前
Qt 中的 QListWidget、QTreeWidget 和 QTableWidget:简化的数据展示控件
c语言·开发语言·c++·qt·c#
六点半88815 分钟前
【C++】速通涉及 “vector” 的经典OJ编程题
开发语言·c++·算法·青少年编程·推荐算法
惜.己15 分钟前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
niu_sama19 分钟前
基于muduo库函数实现protobuf协议的通信
开发语言·qt