-
Notifications
You must be signed in to change notification settings - Fork 2
/
parallelfor.go
74 lines (61 loc) · 1.05 KB
/
parallelfor.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
// parallelfor.go by Jelle van den Hooff
package concurrency
import (
"runtime"
"sync"
"sync/atomic"
)
type GP struct {
max, current, step int64
wg sync.WaitGroup
}
func (gp *GP) Next() (int64, bool) {
base := atomic.AddInt64(&gp.current, gp.step) - gp.step
if base >= gp.max {
return 0, false
} else {
return base, true
}
}
type P struct {
gp *GP
max, current int64
}
func (p *P) Next() (int, bool) {
if p.current >= p.max {
r, ok := p.gp.Next()
if !ok {
return 0, false
}
p.current, p.max = r, r+p.gp.step
if p.max > p.gp.max {
p.max = p.gp.max
}
}
r := p.current
p.current += 1
return int(r), true
}
func ParallelFor(n int, f func(p *P)) {
// TODO: this formula could probably be more clever
step := n / runtime.NumCPU() / 100
if step < 10 {
step = 10
}
gp := &GP{
max: int64(n),
current: 0,
step: int64(step),
}
gp.wg.Add(runtime.NumCPU())
for i := 0; i < runtime.NumCPU(); i++ {
go func() {
p := &P{
gp: gp,
}
f(p)
gp.wg.Done()
}()
}
gp.wg.Wait()
}