github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2012/waza/balance.go (about) 1 // +build OMIT 2 3 package main 4 5 import ( 6 "container/heap" 7 "fmt" 8 "math/rand" 9 "time" 10 ) 11 12 const nRequester = 100 13 const nWorker = 10 14 15 // Simulation of some work: just sleep for a while and report how long. 16 func op() int { 17 n := rand.Int63n(int64(time.Second)) 18 time.Sleep(time.Duration(nWorker * n)) 19 return int(n) 20 } 21 22 type Request struct { 23 fn func() int 24 c chan int 25 } 26 27 func requester(work chan Request) { 28 c := make(chan int) 29 for { 30 time.Sleep(time.Duration(rand.Int63n(int64(nWorker * 2 * time.Second)))) 31 work <- Request{op, c} 32 <-c 33 } 34 } 35 36 type Worker struct { 37 i int 38 requests chan Request 39 pending int 40 } 41 42 func (w *Worker) work(done chan *Worker) { 43 for { 44 req := <-w.requests 45 req.c <- req.fn() 46 done <- w 47 } 48 } 49 50 type Pool []*Worker 51 52 func (p Pool) Len() int { return len(p) } 53 54 func (p Pool) Less(i, j int) bool { 55 return p[i].pending < p[j].pending 56 } 57 58 func (p *Pool) Swap(i, j int) { 59 a := *p 60 a[i], a[j] = a[j], a[i] 61 a[i].i = i 62 a[j].i = j 63 } 64 65 func (p *Pool) Push(x interface{}) { 66 a := *p 67 n := len(a) 68 a = a[0 : n+1] 69 w := x.(*Worker) 70 a[n] = w 71 w.i = n 72 *p = a 73 } 74 75 func (p *Pool) Pop() interface{} { 76 a := *p 77 *p = a[0 : len(a)-1] 78 w := a[len(a)-1] 79 w.i = -1 // for safety 80 return w 81 } 82 83 type Balancer struct { 84 pool Pool 85 done chan *Worker 86 i int 87 } 88 89 func NewBalancer() *Balancer { 90 done := make(chan *Worker, nWorker) 91 b := &Balancer{make(Pool, 0, nWorker), done, 0} 92 for i := 0; i < nWorker; i++ { 93 w := &Worker{requests: make(chan Request, nRequester)} 94 heap.Push(&b.pool, w) 95 go w.work(b.done) 96 } 97 return b 98 } 99 100 func (b *Balancer) balance(work chan Request) { 101 for { 102 select { 103 case req := <-work: 104 b.dispatch(req) 105 case w := <-b.done: 106 b.completed(w) 107 } 108 b.print() 109 } 110 } 111 112 func (b *Balancer) print() { 113 sum := 0 114 sumsq := 0 115 for _, w := range b.pool { 116 fmt.Printf("%d ", w.pending) 117 sum += w.pending 118 sumsq += w.pending * w.pending 119 } 120 avg := float64(sum) / float64(len(b.pool)) 121 variance := float64(sumsq)/float64(len(b.pool)) - avg*avg 122 fmt.Printf(" %.2f %.2f\n", avg, variance) 123 } 124 125 func (b *Balancer) dispatch(req Request) { 126 if false { 127 w := b.pool[b.i] 128 w.requests <- req 129 w.pending++ 130 b.i++ 131 if b.i >= len(b.pool) { 132 b.i = 0 133 } 134 return 135 } 136 137 w := heap.Pop(&b.pool).(*Worker) 138 w.requests <- req 139 w.pending++ 140 // fmt.Printf("started %p; now %d\n", w, w.pending) 141 heap.Push(&b.pool, w) 142 } 143 144 func (b *Balancer) completed(w *Worker) { 145 if false { 146 w.pending-- 147 return 148 } 149 150 w.pending-- 151 // fmt.Printf("finished %p; now %d\n", w, w.pending) 152 heap.Remove(&b.pool, w.i) 153 heap.Push(&b.pool, w) 154 } 155 156 func main() { 157 work := make(chan Request) 158 for i := 0; i < nRequester; i++ { 159 go requester(work) 160 } 161 NewBalancer().balance(work) 162 }