package base import ( "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/utils" "sync/atomic" "time" ) type ElementPool struct { key int32 pool chan interface{} } type ElementProducer struct { times int64 cnt int32 max int32 pool []*ElementPool nf ProduceFunc //正常的生产函数 bf ProduceFunc //保底的生产函数 quit bool } type ProduceFunc func() (interface{}, int32) type ElementProducerMgr struct { producer map[int32]*ElementProducer } var ElementProducerMgrSington = &ElementProducerMgr{ producer: make(map[int32]*ElementProducer), } func CreateElementProducer(max int32, nf, bf ProduceFunc) *ElementProducer { ep := &ElementProducer{ max: max, nf: nf, bf: bf, pool: make([]*ElementPool, max, max), } return ep } func (ep *ElementProducer) Start() { go _start_produce_routine(ep) } func (ep *ElementProducer) Stop() { ep.quit = true } func (ep *ElementProducer) FetchOneElement(key int32) interface{} { if key < 0 || key >= int32(len(ep.pool)) { return nil } pool := ep.pool[key] if pool != nil { select { case d, ok := <-pool.pool: if ok { atomic.AddInt32(&ep.cnt, -1) return d } else { //向下取一个结果 for i := key - 1; i >= 0; i-- { if ep.pool[i] != nil && len(ep.pool[i].pool) != 0 { return ep.FetchOneElement(i) } } d, _ := ep.bf() return d } default: } } //向下取一个结果 for i := key - 1; i >= 0; i-- { if ep.pool[i] != nil && len(ep.pool[i].pool) != 0 { return ep.FetchOneElement(i) } } d, _ := ep.bf() return d } func (ep *ElementProducer) Dump() { logger.Logger.Tracef("[[[[[[[[[[[[[[[total=%v, calcu=%v]]]]]]]]]]]]]]]", ep.cnt, ep.times) for i := 0; i < len(ep.pool); i++ { epp := ep.pool[i] if epp != nil && len(epp.pool) != 0 { logger.Logger.Tracef("[key=%v] [count=%v]", i, len(epp.pool)) } } } func _start_produce_routine(ep *ElementProducer) { defer utils.DumpStackIfPanic("_start_produce_routine") var idle = 0 for !ep.quit { val, key := ep.nf() atomic.AddInt64(&ep.times, 1) if key >= 0 && key < int32(len(ep.pool)) { epp := ep.pool[key] if epp == nil { epp = &ElementPool{key: key, pool: make(chan interface{}, 128)} ep.pool[key] = epp } select { case epp.pool <- val: atomic.AddInt32(&ep.cnt, 1) case <-time.After(time.Millisecond): idle++ } } if idle >= 10000 { idle = 0 //ep.Dump() } } } func (this *ElementProducerMgr) GetProducer(id int32) *ElementProducer { if p, exist := this.producer[id]; exist { return p } return nil } func (this *ElementProducerMgr) SetProducer(id int32, p *ElementProducer) { if op, exist := this.producer[id]; exist { if op != nil { op.Stop() } } this.producer[id] = p } func (this *ElementProducerMgr) StopAll() { for _, p := range this.producer { if p != nil { p.Stop() } } }