gitee.com/h79/goutils@v1.22.10/common/scheduler/pool.go (about)

     1  package scheduler
     2  
     3  import (
     4  	"gitee.com/h79/goutils/common/logger"
     5  	"gitee.com/h79/goutils/common/system"
     6  	"sync/atomic"
     7  	"time"
     8  )
     9  
    10  type IdleHandler interface {
    11  	Idle(num int32)
    12  }
    13  
    14  // IdleFunc idle working number
    15  type IdleFunc func(num int32)
    16  
    17  func (fn IdleFunc) Idle(num int32) {
    18  	fn(num)
    19  }
    20  
    21  type Pool struct {
    22  	jobs        chan *Job
    23  	workers     chan *jobWorker
    24  	stop        chan bool
    25  	delay       *Delay
    26  	tm          *time.Ticker
    27  	numWorkers  int32 //总数
    28  	runWorkers  int32 //正常运行
    29  	idleWorking int32 //空闲worker数
    30  	idleHandler IdleHandler
    31  	running     system.RunningCheck
    32  }
    33  
    34  func NewPool(numWorkers, jobQueueLen int) *Pool {
    35  	if numWorkers <= 0 || jobQueueLen <= 0 {
    36  		panic("length is zero")
    37  	}
    38  	var num = int32(numWorkers)
    39  	pool := &Pool{
    40  		jobs:        make(chan *Job, jobQueueLen),
    41  		workers:     make(chan *jobWorker, numWorkers),
    42  		stop:        make(chan bool),
    43  		delay:       NewDelay(),
    44  		tm:          time.NewTicker(time.Millisecond * 10),
    45  		numWorkers:  num,
    46  		runWorkers:  num,
    47  		idleWorking: num,
    48  	}
    49  	pool.createWorkers(numWorkers)
    50  	pool.Run()
    51  	return pool
    52  }
    53  
    54  func (p *Pool) SetIdleHandler(fn IdleHandler) *Pool {
    55  	p.idleHandler = fn
    56  	return p
    57  }
    58  
    59  func (p *Pool) WithIdleFunc(fn func(num int32)) *Pool {
    60  	return p.SetIdleHandler(IdleFunc(fn))
    61  }
    62  
    63  func (p *Pool) AddJob(job *Job) {
    64  	if job == nil {
    65  		return
    66  	}
    67  	if system.IsQuit() {
    68  		logger.W("Task", "application is quited,not can add for jobId= %s", job.GetId())
    69  		return
    70  	}
    71  	ww := atomic.LoadInt32(&p.runWorkers)
    72  	if ww <= p.numWorkers/2 {
    73  		// 中间有原因,线程池中的线程,由于某些原因,退出了,需要再启动
    74  		p.createWorkers(int(p.numWorkers - ww))
    75  	}
    76  	p.Run()
    77  	p.jobs <- job
    78  }
    79  
    80  func (p *Pool) Run() {
    81  	p.running.GoRunning(p.dispatch)
    82  }
    83  
    84  func (p *Pool) HasWorking() bool {
    85  	return atomic.LoadInt32(&p.idleWorking) != p.numWorkers
    86  }
    87  
    88  func (p *Pool) Release() {
    89  	system.Stop(time.Second, p.stop)
    90  	p.idleHandle(p.numWorkers)
    91  }
    92  
    93  func (p *Pool) createWorkers(num int) {
    94  	for i := 0; i < num; i++ {
    95  		worker := newWorker(p)
    96  		worker.start()
    97  	}
    98  }
    99  
   100  func (p *Pool) idleHandle(idleWork int32) {
   101  	if p.idleHandler != nil {
   102  		p.idleHandler.Idle(idleWork)
   103  	}
   104  }
   105  
   106  func (p *Pool) workerRunning() {
   107  	atomic.AddInt32(&p.runWorkers, 1)
   108  }
   109  
   110  func (p *Pool) workerQuit() {
   111  	atomic.AddInt32(&p.runWorkers, -1)
   112  }
   113  
   114  func (p *Pool) workerIdle() {
   115  	p.idleHandle(atomic.AddInt32(&p.idleWorking, 1))
   116  }
   117  
   118  func (p *Pool) dispatch() {
   119  	defer p.tm.Stop()
   120  	defer p.idleHandle(p.numWorkers)
   121  	for {
   122  		select {
   123  		case <-p.stop:
   124  			p.stopWorks(1)
   125  			p.stop <- true
   126  			return
   127  
   128  		case <-system.Closed():
   129  			p.stopWorks(2)
   130  			return
   131  
   132  		case job := <-p.jobs:
   133  			if job.Delay > 0 {
   134  				p.delayJob(job)
   135  			} else {
   136  				p.executeJob(job)
   137  			}
   138  		case <-p.tm.C:
   139  			p.checkDelayJob()
   140  		}
   141  	}
   142  }
   143  
   144  func (p *Pool) stopWorks(s int) {
   145  	for i := 0; i < len(p.workers); i++ {
   146  		worker := <-p.workers
   147  		worker.stop <- s
   148  		<-worker.stop
   149  	}
   150  	atomic.StoreInt32(&p.idleWorking, p.numWorkers)
   151  	// delay
   152  	opts := With(s)
   153  	p.delay.Exec(opts...)
   154  
   155  	for i := 0; i < len(p.jobs); i++ {
   156  		job, ok := <-p.jobs
   157  		if !ok {
   158  			return
   159  		}
   160  		_, _ = job.Execute(opts...)
   161  	}
   162  }
   163  
   164  func (p *Pool) idleWork(w *jobWorker) {
   165  	if system.IsQuit() {
   166  		return
   167  	}
   168  	p.workers <- w
   169  }
   170  
   171  func (p *Pool) executeJob(job *Job) {
   172  	if system.IsQuit() {
   173  		_, _ = job.Execute(WithQuited())
   174  		return
   175  	}
   176  	worker := <-p.workers
   177  	p.idleHandle(atomic.AddInt32(&p.idleWorking, -1))
   178  	worker.job <- job
   179  }
   180  
   181  func (p *Pool) delayJob(job *Job) {
   182  	p.delay.Add(job)
   183  }
   184  
   185  func (p *Pool) checkDelayJob() {
   186  	p.delay.Check(p)
   187  }