github.com/suiyunonghen/DxCommonLib@v0.5.3/GWorkers.go (about) 1 /* 2 从fasthttp中变更过来的GoRoutine池 3 Autor: 不得闲 4 QQ:75492895 5 */ 6 package DxCommonLib 7 8 import ( 9 _ "go.uber.org/automaxprocs" 10 "runtime" 11 "sync" 12 "time" 13 ) 14 15 type ( 16 GWorkerFunc func(data ...interface{}) 17 GWorkers struct { 18 mustStop bool 19 fMaxWorkersCount int //能同时存在的最多线程个数 20 workersCount int 21 fMaxWorkerIdleTime time.Duration //线程能空闲的最长时间,超过这个时间了会回收掉这个线程 22 ready []*workerChan //准备好的空闲线程 23 lock sync.Mutex 24 workerChanPool sync.Pool //工作者 25 fStopChan chan struct{} 26 } 27 28 workerChan struct { 29 lastUseTime time.Time 30 fOwner *GWorkers 31 fCurTask chan defTaskRunner //ITaskRunner 32 } 33 34 defTaskRunner struct { 35 runFunc GWorkerFunc 36 runArgs []interface{} 37 } 38 ) 39 40 func (workers *GWorkers) Start() { 41 if workers.fStopChan != nil { 42 panic("BUG: GWorkers already started") 43 } 44 workers.fStopChan = make(chan struct{}) 45 stopCh := workers.fStopChan 46 workers.workerChanPool.New = func() interface{} { 47 return &workerChan{ 48 fOwner: workers, 49 fCurTask: make(chan defTaskRunner, workerChanCap), 50 } 51 } 52 go func() { 53 var scratch []*workerChan 54 for { 55 select { 56 case <-stopCh: 57 return 58 case <-After(workers.fMaxWorkerIdleTime): 59 //执行上了 60 workers.clean(&scratch) //定时执行清理回收线程 61 } 62 } 63 }() 64 } 65 66 func (workers *GWorkers) Stop() { 67 if workers.fStopChan == nil { 68 panic("BUG: GWorkers wasn't started") 69 } 70 close(workers.fStopChan) 71 workers.fStopChan = nil 72 73 // Stop all the workers waiting for incoming connections. 74 // Do not wait for busy workers - they will stop after 75 // serving the connection and noticing wp.mustStop = true. 76 workers.lock.Lock() 77 ready := workers.ready 78 l := len(ready) 79 for i := 0; i < l; i++ { 80 ready[i].fCurTask <- defTaskRunner{} 81 ready[i] = nil 82 } 83 workers.ready = ready[:0] 84 workers.mustStop = true 85 workers.lock.Unlock() 86 } 87 88 var workerChanCap = func() int { 89 // Use blocking workerChan if GOMAXPROCS=1. 90 // This immediately switches Serve to WorkerFunc, which results 91 // in higher performance (under go1.5 at least). 92 if runtime.GOMAXPROCS(0) == 1 { 93 return 0 94 } 95 96 // Use non-blocking workerChan if GOMAXPROCS>1, 97 // since otherwise the Serve caller (Acceptor) may lag accepting 98 // new connections if WorkerFunc is CPU-bound. 99 return 1 100 }() 101 102 func (workers *GWorkers) clean(scratch *[]*workerChan) { 103 // Clean least recently used workers if they didn't serve connections 104 // for more than maxIdleWorkerDuration. 105 criticalTime := time.Now().Add(-workers.fMaxWorkerIdleTime) 106 workers.lock.Lock() 107 ready := workers.ready 108 n := len(ready) 109 //超过设定的最大空闲时间的,就解雇掉 110 // Use binary-search algorithm to find out the index of the least recently worker which can be cleaned up. 111 l, r, mid := 0, n-1, 0 112 for l <= r { 113 mid = (l + r) / 2 114 if criticalTime.After(workers.ready[mid].lastUseTime) { 115 l = mid + 1 116 } else { 117 r = mid - 1 118 } 119 } 120 if r == -1 { 121 workers.lock.Unlock() 122 return 123 } 124 i := r 125 *scratch = append((*scratch)[:0], ready[:i+1]...) 126 m := copy(ready, ready[i+1:]) 127 for i = m; i < n; i++ { 128 ready[i] = nil 129 } 130 workers.ready = ready[:m] 131 workers.lock.Unlock() 132 133 // Notify obsolete workers to stop. 134 // This notification must be outside the wp.lock, since ch.ch 135 // may be blocking and may consume a lot of time if many workers 136 // are located on non-local CPUs. 137 tmp := *scratch 138 for i = 0; i < len(tmp); i++ { 139 tmp[i].fCurTask <- defTaskRunner{} 140 tmp[i] = nil 141 } 142 } 143 144 func (workers *GWorkers) getCh() *workerChan { 145 var ch *workerChan 146 createWorker := false 147 148 workers.lock.Lock() 149 ready := workers.ready 150 n := len(ready) - 1 151 if n < 0 { 152 if workers.workersCount < workers.fMaxWorkersCount { 153 createWorker = true 154 workers.workersCount++ 155 } 156 } else { 157 ch = ready[n] 158 ready[n] = nil 159 workers.ready = ready[:n] 160 } 161 workers.lock.Unlock() 162 163 if ch == nil { 164 if !createWorker { 165 return nil 166 } 167 vch := workers.workerChanPool.Get() 168 ch = vch.(*workerChan) 169 go func() { 170 workers.workerFunc(ch) 171 workers.workerChanPool.Put(vch) 172 }() 173 } 174 return ch 175 } 176 177 func (workers *GWorkers) release(ch *workerChan) bool { 178 ch.lastUseTime = time.Now() 179 workers.lock.Lock() 180 if workers.mustStop { 181 workers.lock.Unlock() 182 return false 183 } 184 workers.ready = append(workers.ready, ch) 185 workers.lock.Unlock() 186 return true 187 } 188 189 func (workers *GWorkers) workerFunc(ch *workerChan) { 190 //waitTimes := workers.fMaxWorkerIdleTime + time.Second * 5 191 for { 192 curTask := <-ch.fCurTask 193 if curTask.runFunc == nil { 194 break 195 } 196 curTask.runFunc(curTask.runArgs...) 197 if !workers.release(ch) { 198 break 199 } 200 /*select { 201 case curTask := <-ch.fCurTask: 202 if curTask.runFunc == nil { 203 break 204 } 205 curTask.runFunc(curTask.runArgs...) 206 if !workers.release(ch) { 207 break 208 } 209 case <-After(waitTimes): 210 //这么长时间都没有等到信号,是不是已经跪了 211 //删除这个长期占有的channel 212 workers.lock.Lock() 213 n := len(workers.ready) 214 for i := n - 1;i>=0;i--{ 215 if workers.ready[i] == ch{ 216 if i == n - 1{ 217 workers.ready = workers.ready[:i] 218 }else{ 219 workers.ready = append(workers.ready[:i],workers.ready[i+1:]...) 220 } 221 workers.workersCount-- 222 break 223 } 224 } 225 workers.lock.Unlock() 226 return 227 }*/ 228 } 229 workers.lock.Lock() 230 workers.workersCount-- 231 workers.lock.Unlock() 232 } 233 234 func (workers *GWorkers) PostFunc(routineFunc GWorkerFunc, params ...interface{}) bool { 235 wch := workers.getCh() 236 if wch != nil { 237 wch.fCurTask <- defTaskRunner{ 238 runFunc: routineFunc, 239 runArgs: params, 240 } 241 return true 242 } 243 return false 244 } 245 246 // MustPostFunc 必然投递 247 func (workers *GWorkers) MustPostFunc(routineFunc GWorkerFunc, params ...interface{}) { 248 for { 249 wch := workers.getCh() 250 if wch != nil { 251 wch.fCurTask <- defTaskRunner{ 252 runFunc: routineFunc, 253 runArgs: params, 254 } 255 return 256 } 257 runtime.Gosched() 258 } 259 } 260 261 // MustRunAsync 必须异步执行到 262 func (workers *GWorkers) MustRunAsync(routineFunc GWorkerFunc, params ...interface{}) { 263 for i := 0; i < 10; i++ { 264 wch := workers.getCh() 265 if wch != nil { 266 wch.fCurTask <- defTaskRunner{ 267 runFunc: routineFunc, 268 runArgs: params, 269 } 270 return 271 } 272 runtime.Gosched() 273 } 274 go routineFunc(params...) 275 } 276 277 func (workers *GWorkers) TryPostAndRun(routineFunc GWorkerFunc, params ...interface{}) { 278 for idx := 0; idx < 10; idx++ { 279 wch := workers.getCh() 280 if wch != nil { 281 wch.fCurTask <- defTaskRunner{ 282 runFunc: routineFunc, 283 runArgs: params, 284 } 285 return 286 } 287 runtime.Gosched() 288 } 289 routineFunc(params...) 290 return 291 } 292 293 func NewWorkers(maxGoroutinesAmount int, maxGoroutineIdleDuration time.Duration) *GWorkers { 294 gp := new(GWorkers) 295 if maxGoroutinesAmount <= 0 { 296 gp.fMaxWorkersCount = 512 * 1024 297 } else { 298 gp.fMaxWorkersCount = maxGoroutinesAmount 299 } 300 if maxGoroutineIdleDuration <= 0 { 301 gp.fMaxWorkerIdleTime = 10 * time.Second 302 } else { 303 gp.fMaxWorkerIdleTime = maxGoroutineIdleDuration 304 } 305 gp.Start() 306 return gp 307 } 308 309 var defWorkers *GWorkers 310 311 func ResetDefaultWorker(maxGoroutinesAmount int, maxGoroutineIdleDuration time.Duration) { 312 if defWorkers != nil { 313 defWorkers.Stop() 314 } 315 defWorkers = NewWorkers(maxGoroutinesAmount, maxGoroutineIdleDuration) 316 } 317 318 func PostFunc(routineFunc GWorkerFunc, params ...interface{}) bool { 319 if defWorkers == nil { 320 defWorkers = NewWorkers(0, 0) 321 } 322 return defWorkers.PostFunc(routineFunc, params...) 323 } 324 325 func MustPostFunc(routineFunc GWorkerFunc, params ...interface{}) { 326 if defWorkers == nil { 327 defWorkers = NewWorkers(0, 0) 328 } 329 defWorkers.MustPostFunc(routineFunc, params...) 330 } 331 332 func TryPostAndRun(routineFunc GWorkerFunc, params ...interface{}) { 333 if defWorkers == nil { 334 defWorkers = NewWorkers(0, 0) 335 } 336 defWorkers.TryPostAndRun(routineFunc, params...) 337 } 338 339 // MustRunAsync 必须异步执行到 340 func MustRunAsync(routineFunc GWorkerFunc, params ...interface{}) { 341 if defWorkers == nil { 342 defWorkers = NewWorkers(0, 0) 343 } 344 defWorkers.MustRunAsync(routineFunc, params...) 345 } 346 347 func StopWorkers() { 348 if defWorkers != nil { 349 defWorkers.Stop() 350 } 351 }