-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterval.go
More file actions
85 lines (70 loc) · 1.59 KB
/
interval.go
File metadata and controls
85 lines (70 loc) · 1.59 KB
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
package goutil
import (
"sync"
"time"
)
// Interval runs a callback in an event loop (similar to JavaScript)
type Interval struct {
cb func() bool
ms time.Duration
lastRun int64
id uintptr
mu sync.Mutex
stop bool
}
var intervals []*Interval
var intervalMU sync.Mutex
func init() {
go func() {
for {
time.Sleep(time.Millisecond)
now := time.Now().UnixMilli()
intervalMU.Lock()
for _, interval := range intervals {
if interval.stop {
intervals = append(intervals[:interval.id], intervals[interval.id+1:]...)
continue
}
if now-interval.lastRun < interval.ms.Milliseconds() {
continue
}
interval.lastRun = now
go func() {
interval.mu.Lock()
defer interval.mu.Unlock()
if !interval.stop {
runAgain := interval.cb()
if !runAgain {
interval.stop = true
}
}
}()
}
intervalMU.Unlock()
}
}()
}
// SetInterval runs a callback in an event loop (similar to JavaScript).
//
// This may be useful for concurrently running low priority tasks without creating multiple goroutines.
//
// @cb return:
// - true: continue interval
// - false: break interval
//
// @ms: time in nanoseconds (minimum of 1 millisecond)
func SetInterval(cb func() bool, ms time.Duration) *Interval {
intervalMU.Lock()
defer intervalMU.Unlock()
interval := Interval{
cb: cb,
ms: ms,
id: uintptr(len(intervals)),
}
intervals = append(intervals, &interval)
return &interval
}
// Clear stops the interval and removes it from the queue
func (interval *Interval) Clear() {
interval.stop = true
}