-
Notifications
You must be signed in to change notification settings - Fork 8
/
ticker.go
109 lines (82 loc) · 1.47 KB
/
ticker.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
package kcache
import (
"math/rand"
"time"
)
type ticker interface {
Next() <-chan int
Reset()
Stop()
Done() <-chan struct{}
}
func newTicker(period time.Duration, fuzz float64) ticker {
t := &_ticker{
period: period,
fuzz: fuzz,
nextch: make(chan int),
resetch: make(chan bool),
stopch: make(chan bool),
donech: make(chan struct{}),
}
go t.run()
return t
}
type _ticker struct {
period time.Duration
fuzz float64
nextch chan int
resetch chan bool
stopch chan bool
donech chan struct{}
}
func (t *_ticker) Next() <-chan int {
return t.nextch
}
func (t *_ticker) Reset() {
select {
case t.resetch <- true:
case <-t.donech:
}
}
func (t *_ticker) Stop() {
select {
case t.stopch <- true:
case <-t.donech:
}
}
func (t *_ticker) Done() <-chan struct{} {
return t.donech
}
func (t *_ticker) run() {
defer close(t.donech)
count := 0
timer := time.NewTimer(t.nextPeriod())
var nextch chan int
for {
select {
case <-t.resetch:
if !timer.Stop() {
<-timer.C
}
timer.Reset(t.nextPeriod())
nextch = nil
case <-t.stopch:
timer.Stop()
return
case <-timer.C:
timer.Stop()
nextch = t.nextch
case nextch <- count:
count++
nextch = nil
timer.Reset(t.nextPeriod())
}
}
}
func (t *_ticker) nextPeriod() time.Duration {
delta := t.fuzz * float64(t.period)
min := float64(t.period) - delta
max := float64(t.period) + delta
r := rand.Float64()
return time.Duration(min + r*(max-min+1))
}