/
queue.go
261 lines (238 loc) · 5.73 KB
/
queue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
package taskpool
import (
"fmt"
"sync/atomic"
"sync"
)
// SliceQueuer 多分片队列,分片内权重排序容器
//使用下面代码创建任务队列:
//
// queue := CreateSliceQueue(writeslicenum int, sliceelemnum int) SliceQueuer
//
//使用下面代码放入元素
//
// queue.Put(lvl int64, elem interface{})
//
//
//使用下面代码弹出一个元素 ,如果为空阻塞
//
// queue.PopBlock() SliceElemer
//
//使用下面代码查看容器内有多少各元素
//
// queue.Len() int
//
type SliceQueuer interface {
//将数据插入队列
Put(lvl int64, elem interface{})
//弹出一个数据,如果没有数据则阻塞
PopBlock() SliceElemer
//弹出一个元素,如果没有数据返回nil
Pop() SliceElemer
//容器内元素个数 返回-1容器不可用
Len() int
//关闭队列,此时所有调用PopBlock方法都返回nil
Close()
}
// SliceElemer 分片元素
type SliceElemer interface {
Lvl() int64
Get() interface{}
}
// CreateSliceQueue 创建分片有限队列
//writeslicenum 分片数量
//sliceelemnum 分片内元素数量
func CreateSliceQueue(writeslicenum int, sliceelemnum int) SliceQueuer {
queue := &SliceQueue{}
queue.init(writeslicenum, sliceelemnum)
return queue
}
// SliceQueueOption 分片队列选项
type SliceQueueOption struct {
//切片元素数量
sliceelemnum int
//写入分片数量
writeslicenum int
}
// SliceQueue 分片队列
type SliceQueue struct {
//写锁
writelock sync.Mutex
//写等待信号
writewait *sync.Cond
//读等待信号
readwait *sync.Cond
//写入分片组
writeQueue []PowerLister
//读取分片
readQueue PowerLister
//等待切片最大数量
sliceelemnum int
//写入分片数量
writeslicenum int
size int64
//是否是关闭中
closing bool
//运行中
run bool
}
//初始化队列
func (q *SliceQueue) init(writeslicenum int, sliceelemnum int) {
q.sliceelemnum = sliceelemnum
q.writeslicenum = writeslicenum
q.readwait = sync.NewCond(&sync.Mutex{})
q.writewait = sync.NewCond(&sync.Mutex{})
q.readQueue = q.createSlice()
q.writeQueue = make([]PowerLister, 0)
q.writeQueue = append(q.writeQueue, q.createSlice())
q.run = true
}
//创建分片
func (q *SliceQueue) createSlice() PowerLister {
return NewPowerList()
}
// Len 数量
func (q *SliceQueue) Len() int {
if q.closing || !q.run {
return -1
}
return int(q.size)
}
// Close 关闭队列
func (q *SliceQueue) Close() {
if !q.checkRun() {
return
}
fmt.Println("关闭SliceQueue")
q.readwait.L.Lock()
q.readwait.Broadcast()
q.readwait.L.Unlock()
q.closing = true
q.run = false
}
// Put 放入一个元素lvl为优先级 elem为元素
func (q *SliceQueue) Put(lvl int64, elem interface{}) {
if !q.checkRun() {
return
}
q.writelock.Lock()
defer q.writelock.Unlock()
//当前写入分片
wq := q.writeQueue[len(q.writeQueue)-1]
for wq.Len() >= q.sliceelemnum && !q.checkRun() {
//当前写入分片已经满了
if len(q.writeQueue) >= q.writeslicenum {
//写入分片总数已经满了
q.writewait.L.Lock()
if len(q.writeQueue) >= q.writeslicenum {
//写入分片总数已经满了等待下次被唤醒
q.writewait.Wait()
q.writewait.L.Unlock()
continue
} else {
q.writewait.L.Unlock()
}
}
//创建新的分片
wq = q.createSlice()
q.writeQueue = append(q.writeQueue, wq)
break
}
//将数据插入写入分片
wq.Insert(lvl, elem)
atomic.AddInt64(&q.size, 1)
//发送一个读信号
q.readwait.L.Lock()
q.readwait.Signal()
q.readwait.L.Unlock()
}
// PopBlock 弹出一个元素
func (q *SliceQueue) PopBlock() (elem SliceElemer) {
if !q.checkRun() {
fmt.Println("SliceQueue 没有运行")
return
}
if q.readQueue.Len() > 0 {
//读取分片内有数据
elem = q.readQueue.Pop()
atomic.AddInt64(&q.size, -1)
return
}
//读取分片内没有数据就检测写分片内是否有数据
if q.writeQueue[0].Len() > 0 {
//写入分片内有数据
if len(q.writeQueue) > 1 {
//写分片组有数据有多个分片
q.writelock.Lock()
q.readQueue.Copy(q.writeQueue[0])
q.writeQueue = q.writeQueue[1:]
q.writelock.Unlock()
} else {
//写分片组有数据只有一个分片
q.writelock.Lock()
q.readQueue.Copy(q.writeQueue[0])
q.writeQueue = append(q.writeQueue, q.createSlice())
q.writeQueue = q.writeQueue[1:]
q.writelock.Unlock()
}
//产生一个取走写切片的信号
q.writewait.L.Lock()
q.writewait.Signal()
q.writewait.L.Unlock()
} else {
//写入分片内没有数据进入读等待
if q.writeQueue[0].Len() == 0 {
q.readwait.L.Lock()
if q.writeQueue[0].Len() == 0 {
q.readwait.Wait()
}
q.readwait.L.Unlock()
}
//解锁后弹出元素
}
return q.Pop()
}
func (q *SliceQueue) checkRun() bool {
return !q.closing && q.run
}
// Pop 弹出一个元素
func (q *SliceQueue) Pop() (elem SliceElemer) {
if !q.checkRun() {
return
}
if q.readQueue.Len() > 0 {
//读取分片内有数据
elem = q.readQueue.Pop()
atomic.AddInt64(&q.size, -1)
return
}
//读取分片内没有数据就检测写分片内是否有数据
if q.writeQueue[0].Len() > 0 {
//写入分片内有数据
if len(q.writeQueue) > 1 {
//写分片组有数据切有多个分片
q.writelock.Lock()
q.readQueue.Copy(q.writeQueue[0])
q.writeQueue = q.writeQueue[1:]
q.writelock.Unlock()
} else {
//写分片组有数据切只有一个分片
q.writelock.Lock()
q.readQueue.Copy(q.writeQueue[0])
q.writeQueue = append(q.writeQueue, q.createSlice())
q.writeQueue = q.writeQueue[1:]
q.writelock.Unlock()
}
//产生一个取走写切片的信号
q.writewait.L.Lock()
q.writewait.Signal()
q.writewait.L.Unlock()
} else {
//写入分片内没有数据进入读等待
if q.writeQueue[0].Len() == 0 {
return nil
}
//解锁后弹出元素
}
return q.Pop()
}