-
Notifications
You must be signed in to change notification settings - Fork 1
/
execution_limiter.go
64 lines (55 loc) · 1.9 KB
/
execution_limiter.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
package util
// ExecutionLimiter is a utility which limits the concurrent execution of a
// function. When it is initialized it creates a channel with x capacity and
// fills it with x booleans. Every time the Lock() function is called a bool is
// removed from the channel. When the channel is empty the function will block
// until the Unlock function is called, which puts a new bool into the channel.
type ExecutionLimiter struct {
channel chan struct{}
threads int
}
// NewExecutionLimiter creates a new Exection Limiter. The numThreads parameter
// is how many threads can concurrently execute the function
func NewExecutionLimiter(numThreads int) (el *ExecutionLimiter) {
el = &ExecutionLimiter{
channel: make(chan struct{}, numThreads),
threads: numThreads,
}
// Fill the channel with slots. When the channel is empty the Lock function
// will block until a new struct is fed into the channel through Unlock
for i := 0; i < numThreads; i++ {
el.channel <- struct{}{}
}
return el
}
// Stop the ExecutionLimiter. This destroys the channel. Calling Unlock after
// Stop will panic
func (el *ExecutionLimiter) Stop() { close(el.channel) }
// Drain drains the execution limiter of all slots. This essentially functions
// as the Wait function of a WaitGroup. After Drain the ExecutionLimiter cannot
// be used anymore
func (el *ExecutionLimiter) Drain() {
for i := 0; i < el.threads; i++ {
<-el.channel
}
el.Stop()
}
// Lock the ExecutionLimiter
func (el *ExecutionLimiter) TryLock() (ok bool) {
select {
case <-el.channel:
return true
default:
return false
}
}
// Lock the ExecutionLimiter
func (el *ExecutionLimiter) Lock() { <-el.channel }
// Unlock the ExecutionLimiter
func (el *ExecutionLimiter) Unlock() { el.channel <- struct{}{} }
// Exec obtains an execution slot, runs the provided function and then returns the slot
func (el *ExecutionLimiter) Exec(f func()) {
el.Lock()
f()
el.Unlock()
}