11package queues
22
33import (
4- "context"
54 "github.com/lxzan/concurrency/logs"
6- "sync"
7- "sync/atomic"
5+ "github.com/pkg/errors"
86 "time"
97)
108
@@ -13,10 +11,12 @@ const (
1311 defaultTimeout = 30 * time .Second
1412)
1513
16- var DefaultQueue = New (WithConcurrency ( 16 ), WithRecovery () )
14+ var ErrStopTimeout = errors . New ("stop timeout" )
1715
1816type (
1917 options struct {
18+ multiple bool
19+ size int64
2020 concurrency int64
2121 timeout time.Duration
2222 caller Caller
@@ -25,28 +25,21 @@ type (
2525
2626 Caller func (logger logs.Logger , f func ())
2727
28- queue struct {
29- mu * sync.Mutex // 锁
30- q []Job // 任务队列
31- maxConcurrency int64 // 最大并发
32- curConcurrency int64 // 当前并发
33- caller Caller // 异常处理
34- logger logs.Logger // 日志
35- }
36-
3728 Job func ()
3829
39- Queue struct {
40- options * options
41- serial int64
42- qs []* queue
30+ Queue interface {
31+ // 追加任务
32+ Push (job Job )
33+
34+ // 停止
35+ // 注意: 此方法有阻塞等待任务结束逻辑; 停止后调用Push方法不会产生任何效果.
36+ Stop () error
4337 }
4438)
4539
46- // New
47- // 创建N条并发度为1的任务队列
48- func New (opts ... Option ) * Queue {
40+ func New (opts ... Option ) Queue {
4941 o := & options {
42+ multiple : false ,
5043 concurrency : defaultConcurrency ,
5144 timeout : defaultTimeout ,
5245 caller : func (logger logs.Logger , f func ()) { f () },
@@ -56,93 +49,8 @@ func New(opts ...Option) *Queue {
5649 f (o )
5750 }
5851
59- qs := make ([]* queue , o .concurrency )
60- for i := int64 (0 ); i < o .concurrency ; i ++ {
61- qs [i ] = newQueue (o )
62- }
63- return & Queue {options : o , qs : qs }
64- }
65-
66- // Push 追加任务
67- func (c * Queue ) Push (job Job ) {
68- index := atomic .AddInt64 (& c .serial , 1 ) & (c .options .concurrency - 1 )
69- c .qs [index ].push (job )
70- }
71-
72- // Stop 停止
73- // 可能需要等待一段时间, 直到所有任务执行完成或者超时
74- func (c * Queue ) Stop () {
75- ctx , cancel := context .WithTimeout (context .Background (), c .options .timeout )
76- ticker := time .NewTicker (50 * time .Millisecond )
77- defer func () {
78- cancel ()
79- ticker .Stop ()
80- }()
81-
82- for {
83- select {
84- case <- ticker .C :
85- sum := 0
86- for _ , item := range c .qs {
87- sum += item .len ()
88- }
89- if sum == 0 {
90- return
91- }
92- case <- ctx .Done ():
93- return
94- }
95- }
96- }
97-
98- // newQueue 创建一个任务队列
99- func newQueue (o * options ) * queue {
100- return & queue {
101- mu : & sync.Mutex {},
102- maxConcurrency : 1 ,
103- curConcurrency : 0 ,
104- caller : o .caller ,
105- logger : o .logger ,
106- }
107- }
108-
109- func (c * queue ) len () int {
110- c .mu .Lock ()
111- defer c .mu .Unlock ()
112- return len (c .q )
113- }
114-
115- // 获取一个任务
116- func (c * queue ) getJob (delta int64 ) Job {
117- c .mu .Lock ()
118- defer c .mu .Unlock ()
119- c .curConcurrency += delta
120- if c .curConcurrency >= c .maxConcurrency {
121- return nil
122- }
123- if n := len (c .q ); n == 0 {
124- return nil
125- }
126- var result = c .q [0 ]
127- c .q = c .q [1 :]
128- c .curConcurrency ++
129- return result
130- }
131-
132- // 循环执行任务
133- func (c * queue ) do (job Job ) {
134- for job != nil {
135- c .caller (c .logger , job )
136- job = c .getJob (- 1 )
137- }
138- }
139-
140- // push 追加任务, 有资源空闲的话会立即执行
141- func (c * queue ) push (job Job ) {
142- c .mu .Lock ()
143- c .q = append (c .q , job )
144- c .mu .Unlock ()
145- if item := c .getJob (0 ); item != nil {
146- go c .do (item )
52+ if o .multiple {
53+ return newMultipleQueue (o )
14754 }
55+ return newSingleQueue (o )
14856}
0 commit comments