github.com/zly-app/zapp@v1.3.3/component/gpool/gpool.go (about) 1 /* 2 ------------------------------------------------- 3 Author : zlyuancn 4 date: 2021/3/19 5 Description : 6 ------------------------------------------------- 7 */ 8 9 package gpool 10 11 import ( 12 "sync" 13 14 "github.com/zly-app/zapp/core" 15 ) 16 17 // 协程池 18 type gpool struct { 19 workerQueue chan *worker // 工人队列 20 jobQueue chan *job // 任务队列 21 stop chan struct{} // 停止信号, 同步通道 22 23 wg sync.WaitGroup 24 } 25 26 func NewGPool(conf *GPoolConfig) core.IGPool { 27 conf.check() 28 if conf.ThreadCount < 0 { 29 return NewNoPool() 30 } 31 32 g := &gpool{ 33 workerQueue: make(chan *worker, conf.ThreadCount), 34 jobQueue: make(chan *job, conf.JobQueueSize), 35 stop: make(chan struct{}), 36 } 37 38 for i := 0; i < conf.ThreadCount; i++ { 39 worker := newWorker(g.workerQueue) 40 worker.Ready() 41 g.workerQueue <- worker 42 } 43 44 go g.dispatch() 45 46 return g 47 } 48 49 // 为工人派遣任务 50 func (g *gpool) dispatch() { 51 var worker *worker 52 var stop bool 53 for !stop { 54 if worker == nil { 55 select { 56 case w := <-g.workerQueue: 57 worker = w 58 case <-g.stop: 59 stop = true 60 continue 61 } 62 } 63 64 select { 65 case job := <-g.jobQueue: 66 worker.Do(job) 67 worker = nil 68 case <-g.stop: 69 stop = true 70 } 71 } 72 73 // 释放worker 74 if worker != nil { 75 worker.Do(nil) // 让这个工人回到池 76 } 77 for i := 0; i < cap(g.workerQueue); i++ { 78 w := <-g.workerQueue 79 w.Stop() 80 } 81 g.workerQueue = nil 82 83 // 释放job 84 jobLen := len(g.jobQueue) 85 g.jobQueue = nil 86 for i := 0; i < jobLen; i++ { 87 g.wg.Done() 88 } 89 90 g.stop <- struct{}{} 91 } 92 93 // 异步执行, 如果队列任务已满则阻塞等待直到有空位 94 func (g *gpool) Go(fn func() error, callback func(err error)) { 95 job := g.newJob(fn, callback) 96 g.jobQueue <- job 97 } 98 99 // 同步执行 100 func (g *gpool) GoSync(fn func() error) (result error) { 101 var wg sync.WaitGroup 102 wg.Add(1) 103 g.Go(fn, func(err error) { 104 result = err 105 wg.Done() 106 }) 107 wg.Wait() 108 return result 109 } 110 111 // 尝试异步执行, 如果任务队列已满则返回false 112 func (g *gpool) TryGo(fn func() error, callback func(err error)) (ok bool) { 113 job := g.newJob(fn, callback) 114 select { 115 case g.jobQueue <- job: 116 return true 117 default: 118 g.wg.Done() 119 return false 120 } 121 } 122 123 // 尝试同步执行, 如果任务队列已满则返回false 124 func (g *gpool) TryGoSync(fn func() error) (result error, ok bool) { 125 var wg sync.WaitGroup 126 wg.Add(1) 127 ok = g.TryGo(fn, func(err error) { 128 result = err 129 wg.Done() 130 }) 131 if ok { 132 wg.Wait() 133 } 134 return 135 } 136 137 // 执行等待所有函数完成 138 func (g *gpool) GoAndWait(fn ...func() error) error { 139 if len(fn) == 0 { 140 return nil 141 } 142 143 var wg sync.WaitGroup 144 errChan := make(chan error, len(fn)) 145 146 for _, f := range fn { 147 wg.Add(1) 148 g.Go(f, func(err error) { 149 if err != nil { 150 errChan <- err 151 } 152 wg.Done() 153 }) 154 } 155 wg.Wait() 156 157 var err error 158 select { 159 case err = <-errChan: 160 default: 161 } 162 return err 163 } 164 165 // 等待队列中所有的任务结束 166 func (g *gpool) Wait() { 167 g.wg.Wait() 168 } 169 170 // 关闭 171 // 172 // 命令所有没有收到任务的工人立即停工, 收到任务的工人完成当前任务后停工, 不管任务队列是否清空. 173 // 表现为加入队列的任务不一定会执行, 但是正在执行的任务不会被取消并会等待这些任务执行完毕. 174 func (g *gpool) Close() { 175 g.stop <- struct{}{} 176 <-g.stop 177 } 178 179 func (g *gpool) newJob(fn func() error, callback func(err error)) *job { 180 g.wg.Add(1) 181 return newJob(fn, func(err error) { 182 g.wg.Done() 183 if callback != nil { 184 callback(err) 185 } 186 }) 187 }