package routinepool import ( "crypto/md5" "encoding/binary" "fmt" "runtime/debug" "gitrosy.jxc4.com/baseapi/utils" ) const ( chanPoolSize = 1000 ) type TaskParam struct { handler func() resultChan chan interface{} } type Pool struct { minRoutineCount int maxRoutineCount int // not used currently curRoutineCount int taskChans []chan *TaskParam } func New(minRoutineCount, maxRoutineCount int) *Pool { if minRoutineCount < 0 || minRoutineCount > maxRoutineCount { panic(fmt.Sprintf("wrong params, minRoutineCount:%d, maxRoutineCount:%d", minRoutineCount, maxRoutineCount)) } retVal := &Pool{ minRoutineCount: minRoutineCount, maxRoutineCount: maxRoutineCount, } retVal.curRoutineCount = minRoutineCount if retVal.curRoutineCount > 0 { retVal.taskChans = make([]chan *TaskParam, retVal.curRoutineCount, retVal.maxRoutineCount) for i := 0; i < retVal.curRoutineCount; i++ { retVal.taskChans[i] = make(chan *TaskParam, chanPoolSize) go taskFun(retVal.taskChans[i], i) } } return retVal } func callHandler(handler func()) (retVal interface{}) { defer func() { if r := recover(); r != nil { retVal = r debug.PrintStack() } }() handler() return retVal } func taskFun(taskChan chan *TaskParam, index int) { for { taskParam := <-taskChan result := callHandler(taskParam.handler) if taskParam.resultChan != nil { taskParam.resultChan <- result } } } func (p *Pool) callFun(func4Call func(), primaryID string, isAsync bool) (r interface{}) { result := md5.Sum([]byte(primaryID + utils.GetUUID())) resultInt64 := int64(binary.LittleEndian.Uint32(result[8:])) chanIndex := int(resultInt64 % int64(p.curRoutineCount)) chanParam := &TaskParam{ handler: func4Call, } if !isAsync { chanParam.resultChan = make(chan interface{}) } p.taskChans[chanIndex] <- chanParam if !isAsync { r = <-chanParam.resultChan close(chanParam.resultChan) } return r } func (p *Pool) CallFun(func4Call func(), primaryID string) { if p.curRoutineCount > 0 { r := p.callFun(func4Call, primaryID, false) if r != nil { panic(r) } } else { func4Call() } } func (p *Pool) CallFunAsync(func4Call func(), primaryID string) { if p.curRoutineCount == 0 { panic("CallFunAsync can not run when p.curRoutineCount == 0") } utils.CallFuncAsync(func() { p.callFun(func4Call, primaryID, true) }) }