blob: c54dd348510cba0fa50acb32033fce06ccf3751d (
plain)
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
|
// Package cardio enables Go programs to speed up and slow down based on demand.
package cardio
import (
"context"
"sync"
"time"
)
// Heartbeat is a function that creates a "heartbeat" channel that you can influence to go faster
// or slower. This is intended to model the behavior of the human heart's ability to slow down and
// speed up based on physical activity.
//
// The basic usage is something like this:
//
// heartbeat, slower, faster := cardio.Heartbeat(ctx, time.Minute, time.Millisecond)
//
// The min and max arguments control the minimum and maximum heart rate. This returns three things:
//
// - The heartbeat channel that your event loop will poll on
// - A function to influence the heartbeat to slow down (beacuse there isn't work to do)
// - A function to influence the heartbeat to speed up (because there is work to do)
//
// Your event loop should look something like this:
//
// for range heartbeat {
// // do something
// if noWork {
// slower()
// } else {
// faster()
// }
// }
//
// This will let you have a dynamically adjusting heartbeat for when your sick, twisted desires
// demand it.
func Heartbeat(ctx context.Context, min, max time.Duration) (<-chan struct{}, func(), func()) {
heartbeat := make(chan struct{}, 1) // output channel
currDelay := max // start at max speed
var currDelayLock sync.Mutex
slower := func() {
currDelayLock.Lock()
currDelay = currDelay / 2
if currDelay < min {
currDelay = min
}
currDelayLock.Unlock()
}
faster := func() {
currDelayLock.Lock()
currDelay = currDelay * 2
if currDelay > max {
currDelay = max
}
currDelayLock.Unlock()
}
go func() {
for {
select {
case <-ctx.Done():
close(heartbeat)
return
default:
currDelayLock.Lock()
toSleep := currDelay
currDelayLock.Unlock()
time.Sleep(toSleep)
select {
case heartbeat <- struct{}{}:
default:
slower() // back off if the channel is full
}
}
}
}()
return heartbeat, slower, faster
}
|