2018-02-02 15:19:42 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
|
|
// You can obtain one at https://gitee.com/johng/gf.
|
|
|
|
|
|
|
2018-02-28 12:01:14 +08:00
|
|
|
|
// 并发安全的动态队列.
|
2018-02-07 09:42:18 +08:00
|
|
|
|
// 优点:
|
|
|
|
|
|
// 1、队列初始化速度快;
|
|
|
|
|
|
// 2、可以向队头/队尾进行Push/Pop操作;
|
2018-02-02 15:19:42 +08:00
|
|
|
|
package gqueue
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"math"
|
|
|
|
|
|
"sync"
|
2018-02-02 16:56:53 +08:00
|
|
|
|
"errors"
|
2018-02-07 09:42:18 +08:00
|
|
|
|
"container/list"
|
2018-02-02 15:19:42 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type Queue struct {
|
|
|
|
|
|
mu sync.RWMutex
|
2018-02-02 16:56:53 +08:00
|
|
|
|
list *list.List // 数据队列
|
|
|
|
|
|
limit int // 队列限制大小
|
|
|
|
|
|
limits chan struct{} // 用于队列大小限制
|
|
|
|
|
|
events chan struct{} // 用于内部数据写入事件通知
|
2018-02-28 11:45:06 +08:00
|
|
|
|
closed bool // 队列是否关闭
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-02 16:56:53 +08:00
|
|
|
|
// 队列大小为非必须参数,默认不限制
|
|
|
|
|
|
func New(limit...int) *Queue {
|
|
|
|
|
|
size := 0
|
|
|
|
|
|
if len(limit) > 0 {
|
|
|
|
|
|
size = limit[0]
|
|
|
|
|
|
}
|
2018-02-02 15:19:42 +08:00
|
|
|
|
return &Queue {
|
|
|
|
|
|
list : list.New(),
|
2018-02-02 16:56:53 +08:00
|
|
|
|
limits : make(chan struct{}, size),
|
2018-02-02 15:19:42 +08:00
|
|
|
|
events : make(chan struct{}, math.MaxInt64),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将数据压入队列, 队尾
|
2018-02-02 16:56:53 +08:00
|
|
|
|
func (q *Queue) PushBack(v interface{}) error {
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.RLock()
|
|
|
|
|
|
if q.closed {
|
|
|
|
|
|
q.mu.RUnlock()
|
2018-02-07 09:42:18 +08:00
|
|
|
|
return errors.New("closed")
|
2018-02-02 16:56:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
if q.limit > 0 {
|
|
|
|
|
|
q.limits <- struct{}{}
|
|
|
|
|
|
}
|
2018-02-02 15:19:42 +08:00
|
|
|
|
q.list.PushBack(v)
|
|
|
|
|
|
q.events <- struct{}{}
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.RUnlock()
|
2018-02-02 16:56:53 +08:00
|
|
|
|
return nil
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将数据压入队列, 队头
|
2018-02-02 16:56:53 +08:00
|
|
|
|
func (q *Queue) PushFront(v interface{}) error {
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.RLock()
|
|
|
|
|
|
if q.closed {
|
|
|
|
|
|
q.mu.RUnlock()
|
2018-02-07 09:42:18 +08:00
|
|
|
|
return errors.New("closed")
|
2018-02-02 16:56:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
if q.limit > 0 {
|
|
|
|
|
|
q.limits <- struct{}{}
|
|
|
|
|
|
}
|
2018-02-02 15:19:42 +08:00
|
|
|
|
q.list.PushFront(v)
|
|
|
|
|
|
q.events <- struct{}{}
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.RUnlock()
|
2018-02-02 16:56:53 +08:00
|
|
|
|
return nil
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从队头先进先出地从队列取出一项数据,当没有数据可获取时,阻塞等待
|
2018-02-02 16:56:53 +08:00
|
|
|
|
func (q *Queue) PopFront() interface{} {
|
2018-02-07 10:52:18 +08:00
|
|
|
|
<- q.events
|
|
|
|
|
|
if q.limit > 0 {
|
|
|
|
|
|
<- q.limits
|
|
|
|
|
|
}
|
|
|
|
|
|
if elem := q.list.Front(); elem != nil {
|
|
|
|
|
|
item := q.list.Remove(elem)
|
|
|
|
|
|
return item
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
2018-02-02 16:56:53 +08:00
|
|
|
|
return nil
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从队尾先进先出地从队列取出一项数据,当没有数据可获取时,阻塞等待
|
2018-02-02 16:56:53 +08:00
|
|
|
|
func (q *Queue) PopBack() interface{} {
|
2018-02-07 10:52:18 +08:00
|
|
|
|
<- q.events
|
|
|
|
|
|
if q.limit > 0 {
|
|
|
|
|
|
<- q.limits
|
|
|
|
|
|
}
|
|
|
|
|
|
if elem := q.list.Front(); elem != nil {
|
|
|
|
|
|
item := q.list.Remove(elem)
|
|
|
|
|
|
return item
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
2018-02-02 16:56:53 +08:00
|
|
|
|
return nil
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-07 09:42:18 +08:00
|
|
|
|
// 关闭队列(通知所有通过Pop*阻塞的协程退出)
|
2018-02-02 15:19:42 +08:00
|
|
|
|
func (q *Queue) Close() {
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.Lock()
|
|
|
|
|
|
if !q.closed {
|
|
|
|
|
|
q.closed = true
|
2018-02-02 16:56:53 +08:00
|
|
|
|
close(q.limits)
|
|
|
|
|
|
close(q.events)
|
|
|
|
|
|
}
|
2018-02-28 11:45:06 +08:00
|
|
|
|
q.mu.Unlock()
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前队列大小
|
|
|
|
|
|
func (q *Queue) Size() int {
|
|
|
|
|
|
return len(q.events)
|
|
|
|
|
|
}
|