2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-02-02 15:19:42 +08:00
|
|
|
|
//
|
|
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-02-02 15:19:42 +08:00
|
|
|
|
|
2019-01-15 23:27:47 +08:00
|
|
|
|
// Package gqueue provides a dynamic/static concurrent-safe(alternative) queue.
|
2019-01-16 13:35:16 +08:00
|
|
|
|
//
|
2019-01-30 21:27:03 +08:00
|
|
|
|
// 并发安全动态队列.
|
2019-01-16 13:35:16 +08:00
|
|
|
|
//
|
|
|
|
|
|
// 特点:
|
|
|
|
|
|
// 1. 动态队列初始化速度快;
|
|
|
|
|
|
// 2. 动态的队列大小(不限大小);
|
|
|
|
|
|
// 3. 取数据时如果队列为空那么会阻塞等待;
|
2018-02-02 15:19:42 +08:00
|
|
|
|
package gqueue
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2019-03-08 17:54:50 +08:00
|
|
|
|
"github.com/gogf/gf/g/container/glist"
|
2018-02-02 15:19:42 +08:00
|
|
|
|
"math"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2019-01-16 13:35:16 +08:00
|
|
|
|
// 1、这是一个先进先出的队列(chan <-- list);
|
|
|
|
|
|
//
|
|
|
|
|
|
// 2、当创建Queue对象时限定大小,那么等同于一个同步的chan并发安全队列;
|
|
|
|
|
|
//
|
|
|
|
|
|
// 3、不限制大小时,list链表用以存储数据,临时chan负责为客户端读取数据,当从chan获取数据时,list往chan中不停补充数据;
|
|
|
|
|
|
//
|
|
|
|
|
|
// 4、由于功能主体是chan,那么操作仍然像chan那样具有阻塞效果;
|
2018-02-02 15:19:42 +08:00
|
|
|
|
type Queue struct {
|
2018-09-16 10:51:02 +08:00
|
|
|
|
limit int // 队列限制大小
|
2019-03-08 17:54:50 +08:00
|
|
|
|
list *glist.List // 底层数据链表
|
2019-01-09 12:54:37 +08:00
|
|
|
|
events chan struct{} // 写入事件通知
|
|
|
|
|
|
closed chan struct{} // 队列关闭通知
|
|
|
|
|
|
C chan interface{} // 队列数据读取
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-15 16:40:13 +08:00
|
|
|
|
const (
|
2018-11-18 22:22:44 +08:00
|
|
|
|
// 动态队列缓冲区大小
|
2019-01-09 12:54:37 +08:00
|
|
|
|
gDEFAULT_QUEUE_SIZE = 10000
|
2018-09-15 16:40:13 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2018-02-02 16:56:53 +08:00
|
|
|
|
// 队列大小为非必须参数,默认不限制
|
|
|
|
|
|
func New(limit...int) *Queue {
|
2018-09-15 16:40:13 +08:00
|
|
|
|
q := &Queue {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
closed : make(chan struct{}, 0),
|
2018-09-16 10:51:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
if len(limit) > 0 {
|
2018-11-18 22:22:44 +08:00
|
|
|
|
q.limit = limit[0]
|
2019-01-09 12:54:37 +08:00
|
|
|
|
q.C = make(chan interface{}, limit[0])
|
2018-09-16 10:51:02 +08:00
|
|
|
|
} else {
|
2019-03-08 17:54:50 +08:00
|
|
|
|
q.list = glist.New()
|
2018-11-18 22:22:44 +08:00
|
|
|
|
q.events = make(chan struct{}, math.MaxInt32)
|
2019-01-09 12:54:37 +08:00
|
|
|
|
q.C = make(chan interface{}, gDEFAULT_QUEUE_SIZE)
|
2018-09-16 10:51:02 +08:00
|
|
|
|
go q.startAsyncLoop()
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
2018-09-15 16:40:13 +08:00
|
|
|
|
return q
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-15 16:40:13 +08:00
|
|
|
|
// 异步list->chan同步队列
|
|
|
|
|
|
func (q *Queue) startAsyncLoop() {
|
|
|
|
|
|
for {
|
2018-09-16 10:51:02 +08:00
|
|
|
|
select {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
case <- q.closed:
|
2018-09-16 10:51:02 +08:00
|
|
|
|
return
|
|
|
|
|
|
case <- q.events:
|
2018-09-18 00:01:10 +08:00
|
|
|
|
for {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
if length := q.list.Len(); length > 0 {
|
|
|
|
|
|
array := make([]interface{}, length)
|
|
|
|
|
|
for i := 0; i < length; i++ {
|
|
|
|
|
|
if e := q.list.Front(); e != nil {
|
|
|
|
|
|
array[i] = q.list.Remove(e)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for _, v := range array {
|
|
|
|
|
|
q.C <- v
|
|
|
|
|
|
}
|
2018-09-18 00:01:10 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2018-09-16 10:51:02 +08:00
|
|
|
|
}
|
2018-09-15 16:40:13 +08:00
|
|
|
|
}
|
2018-03-13 15:54:56 +08:00
|
|
|
|
}
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-09 12:54:37 +08:00
|
|
|
|
// 将数据压入队列, 队尾
|
2018-09-15 16:40:13 +08:00
|
|
|
|
func (q *Queue) Push(v interface{}) {
|
2018-02-02 16:56:53 +08:00
|
|
|
|
if q.limit > 0 {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
q.C <- v
|
2018-03-13 15:54:56 +08:00
|
|
|
|
} else {
|
2018-09-15 16:40:13 +08:00
|
|
|
|
q.list.PushBack(v)
|
2019-01-09 12:54:37 +08:00
|
|
|
|
q.events <- struct{}{}
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-15 16:40:13 +08:00
|
|
|
|
// 从队头先进先出地从队列取出一项数据
|
|
|
|
|
|
func (q *Queue) Pop() interface{} {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
return <- q.C
|
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() {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
close(q.C)
|
2018-09-15 16:40:13 +08:00
|
|
|
|
close(q.events)
|
2019-01-09 12:54:37 +08:00
|
|
|
|
close(q.closed)
|
2018-02-02 15:19:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前队列大小
|
|
|
|
|
|
func (q *Queue) Size() int {
|
2019-01-09 12:54:37 +08:00
|
|
|
|
return len(q.C) + q.list.Len()
|
2018-03-13 15:54:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-29 13:46:05 +08:00
|
|
|
|
|