我这个场景是做优先级的任务派发的,因为有几十个厂商,每个厂商还有不同的业务,每个业务也有10个优先级,这样算来整个任务缓冲池里最少又要几百个队列。 这里没用channel,因为channel通道太多,没法很好的做输出。 优先级肯定是有调度器主动去pop数据,这里选择了使用container/list提供的双端列表。
我的服务主要体现在Push, Pop 类似的操作上,container/list都可以O(1)的时间复杂度。
话题说 list 有个 remove的问题… 你遍历整个链表会发现只会删除第一个,当再次迭代的时候,e.Next() == nil 空值,跳出循环。。。
1 2 3 |
for e := l.Front(); e != nil; e = e.Next() { l.Remove(e) } |
为什么会出现这个问题,我们可以看下 golang list 关于 remove方法的实现。 e.next = nil 注释是说,为了防止内存泄露…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// remove removes e from its list, decrements l.len, and returns e. func (l *List) remove(e *Element) *Element { e.prev.next = e.next e.next.prev = e.prev e.next = nil // avoid memory leaks e.prev = nil // avoid memory leaks e.list = nil l.len-- return e } // Remove removes e from l if e is an element of list l. // It returns the element value e.Value. func (l *List) Remove(e *Element) interface{} { if e.list == l { // if e.list == l, l must have been initialized when e was inserted // in l or l == nil (e is a zero Element) and l.remove will crash l.remove(e) } return e.Value } |
那么我们该如何解决?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var next *list.Element task = nil next = nil pri_list := qname[i] for e := pri_list.Queue.Front(); e != nil; e = next { next = e.Next() // 在这里 fmt.Println(e) pri_list.Queue.Remove(e) task = e.Value.(*dao.MainTask) break } b.BigLock.Unlock() if task == nil { continue } b.FastBuffer <- task c += 1 |
END
有疑问加站长微信联系(非本文作者)