working multi
Vladimir Bauer
9 years ago
| 67 | 67 | Alpha float64 |
| 68 | 68 | |
| 69 | 69 | incrRequestCh chan *incrRequest |
| 70 | incrCh chan int | |
| 70 | 71 | |
| 71 | 72 | redrawRequestCh chan *redrawRequest |
| 72 | 73 | |
| 78 | 79 | |
| 79 | 80 | stopCh chan struct{} |
| 80 | 81 | done chan struct{} |
| 81 | ||
| 82 | // wg *sync.WaitGroup | |
| 83 | 82 | } |
| 84 | 83 | |
| 85 | 84 | type Statistics struct { |
| 113 | 112 | flushedCh: make(chan struct{}), |
| 114 | 113 | stopCh: make(chan struct{}), |
| 115 | 114 | done: make(chan struct{}), |
| 115 | incrCh: make(chan int), | |
| 116 | 116 | } |
| 117 | 117 | go b.server(wg) |
| 118 | 118 | return b |
| 154 | 154 | |
| 155 | 155 | // String returns the string representation of the bar |
| 156 | 156 | func (b *Bar) String() string { |
| 157 | if b.IsStopped() { | |
| 158 | return "bar stopped" | |
| 159 | } | |
| 157 | // if b.IsStopped() { | |
| 158 | // return "bar stopped" | |
| 159 | // } | |
| 160 | 160 | bufCh := make(chan []byte) |
| 161 | 161 | b.redrawRequestCh <- &redrawRequest{bufCh} |
| 162 | 162 | return string(<-bufCh) |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | 165 | func (b *Bar) flushed() { |
| 166 | if !b.IsStopped() { | |
| 167 | b.flushedCh <- struct{}{} | |
| 168 | } | |
| 169 | } | |
| 170 | ||
| 171 | func (b *Bar) Incr(n int) bool { | |
| 172 | if b.IsStopped() { | |
| 173 | return false | |
| 174 | } | |
| 175 | result := make(chan bool) | |
| 176 | b.incrRequestCh <- &incrRequest{n, result} | |
| 177 | return <-result | |
| 166 | b.flushedCh <- struct{}{} | |
| 167 | } | |
| 168 | ||
| 169 | func (b *Bar) Incr(n int) { | |
| 170 | // result := make(chan bool) | |
| 171 | // b.incrRequestCh <- &incrRequest{n, result} | |
| 172 | // return <-result | |
| 173 | if !b.IsCompleted() { | |
| 174 | b.incrCh <- n | |
| 175 | } | |
| 178 | 176 | } |
| 179 | 177 | |
| 180 | 178 | func (b *Bar) server(wg *sync.WaitGroup) { |
| 186 | 184 | var done bool |
| 187 | 185 | for { |
| 188 | 186 | select { |
| 189 | case r := <-b.incrRequestCh: | |
| 190 | n := completed + r.amount | |
| 191 | fmt.Fprintf(os.Stderr, "n = %+v\n", n) | |
| 187 | case i := <-b.incrCh: | |
| 188 | n := completed + i | |
| 192 | 189 | if n > b.total { |
| 193 | r.result <- false | |
| 194 | 190 | completed = b.total |
| 195 | fmt.Fprintln(os.Stderr, "n > b.total = return false") | |
| 196 | break // breaks out of select | |
| 197 | } | |
| 198 | // r.result <- true | |
| 199 | b.updateTimePerItemEstimate(r.amount, blockStartTime) | |
| 191 | break | |
| 192 | } | |
| 193 | b.updateTimePerItemEstimate(i, blockStartTime) | |
| 200 | 194 | completed = n |
| 195 | if completed == b.total && !done { | |
| 196 | done = true | |
| 197 | } | |
| 201 | 198 | blockStartTime = time.Now() |
| 202 | if completed == b.total && !done { | |
| 203 | fmt.Fprintln(os.Stderr, "completed == b.total") | |
| 204 | done = true | |
| 205 | wg.Done() | |
| 206 | } | |
| 207 | r.result <- true | |
| 208 | 199 | case d := <-b.decoratorCh: |
| 209 | 200 | switch d.kind { |
| 210 | 201 | case decoratorAppend: |
| 213 | 204 | prependFuncs = append(prependFuncs, d.f) |
| 214 | 205 | } |
| 215 | 206 | case r := <-b.redrawRequestCh: |
| 216 | // fmt.Fprintln(os.Stderr, "redraw") | |
| 217 | 207 | r.bufCh <- b.draw(buf, completed, appendFuncs, prependFuncs) |
| 218 | // case <-b.flushedCh: | |
| 219 | // if completed == b.total && !done { | |
| 220 | // fmt.Fprintln(os.Stderr, "wg.Done") | |
| 221 | // done = true | |
| 222 | // wg.Done() | |
| 223 | // } else { | |
| 224 | // fmt.Fprintln(os.Stderr, "wg.Done not done") | |
| 225 | // } | |
| 208 | case <-b.flushedCh: | |
| 209 | if done && !b.IsCompleted() { | |
| 210 | fmt.Fprintln(os.Stderr, "flushedCh: wg.Done") | |
| 211 | close(b.done) | |
| 212 | wg.Done() | |
| 213 | } | |
| 226 | 214 | case <-b.stopCh: |
| 227 | 215 | fmt.Fprintln(os.Stderr, "received stop signal") |
| 228 | // close(b.incrRequestCh) | |
| 229 | close(b.done) | |
| 230 | 216 | if !done { |
| 217 | fmt.Fprintln(os.Stderr, "closing done chan: done = false") | |
| 218 | close(b.done) | |
| 231 | 219 | done = true |
| 232 | 220 | wg.Done() |
| 233 | 221 | } |
| 234 | // close(b.redrawRequestCh) | |
| 235 | // close(b.flushedCh) | |
| 236 | 222 | return |
| 237 | 223 | } |
| 238 | 224 | } |
| 239 | 225 | } |
| 240 | 226 | |
| 241 | 227 | func (b *Bar) Stop() { |
| 242 | if !b.IsStopped() { | |
| 243 | fmt.Fprintln(os.Stderr, "sending to stopCh") | |
| 244 | b.stopCh <- struct{}{} | |
| 245 | } else { | |
| 246 | fmt.Fprintln(os.Stderr, "Stop: already stopped") | |
| 247 | } | |
| 248 | } | |
| 249 | ||
| 250 | func (b *Bar) IsStopped() bool { | |
| 228 | b.stopCh <- struct{}{} | |
| 229 | // if !b.IsCompleted() { | |
| 230 | // fmt.Fprintln(os.Stderr, "sending to stopCh") | |
| 231 | // } else { | |
| 232 | // fmt.Fprintln(os.Stderr, "Stop: already stopped") | |
| 233 | // } | |
| 234 | } | |
| 235 | ||
| 236 | func (b *Bar) IsCompleted() bool { | |
| 251 | 237 | select { |
| 252 | 238 | case <-b.done: |
| 253 | 239 | return true |
| 0 | 0 | package main |
| 1 | 1 | |
| 2 | 2 | import ( |
| 3 | "sync" | |
| 3 | "fmt" | |
| 4 | "math/rand" | |
| 5 | "runtime" | |
| 4 | 6 | "time" |
| 5 | 7 | |
| 6 | 8 | "github.com/vbauerster/uiprogress" |
| 7 | 9 | ) |
| 8 | 10 | |
| 11 | const ( | |
| 12 | maxBlockSize = 14 | |
| 13 | ) | |
| 14 | ||
| 9 | 15 | func main() { |
| 10 | waitTime := time.Millisecond * 100 | |
| 11 | // p := uiprogress.New().RefreshInterval(100 * time.Millisecond) | |
| 16 | runtime.GOMAXPROCS(runtime.NumCPU()) | |
| 17 | ||
| 18 | decor := func(s *uiprogress.Statistics) string { | |
| 19 | str := fmt.Sprintf("%d/%d", s.Completed, s.Total) | |
| 20 | return fmt.Sprintf("%-7s", str) | |
| 21 | } | |
| 22 | ||
| 12 | 23 | p := uiprogress.New() |
| 13 | 24 | |
| 14 | var wg sync.WaitGroup | |
| 15 | bar1 := p.AddBar(20).AppendCompleted().PrependElapsed() | |
| 16 | wg.Add(1) | |
| 25 | bar1 := p.AddBar(50).AppendETA().PrependFunc(decor) | |
| 17 | 26 | go func() { |
| 18 | defer wg.Done() | |
| 19 | for bar1.Incr() { | |
| 20 | time.Sleep(waitTime) | |
| 27 | blockSize := rand.Intn(maxBlockSize) + 1 | |
| 28 | for i := 0; i < 50; i++ { | |
| 29 | time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) | |
| 30 | bar1.Incr(1) | |
| 31 | blockSize = rand.Intn(maxBlockSize) + 1 | |
| 21 | 32 | } |
| 22 | 33 | }() |
| 23 | 34 | |
| 24 | bar2 := p.AddBar(40).AppendCompleted().PrependElapsed() | |
| 25 | wg.Add(1) | |
| 35 | bar2 := p.AddBar(100).AppendETA().PrependFunc(decor) | |
| 26 | 36 | go func() { |
| 27 | defer wg.Done() | |
| 28 | for bar2.Incr() { | |
| 29 | time.Sleep(waitTime) | |
| 37 | blockSize := rand.Intn(maxBlockSize) + 1 | |
| 38 | for i := 0; i < 100; i++ { | |
| 39 | time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) | |
| 40 | bar2.Incr(1) | |
| 41 | blockSize = rand.Intn(maxBlockSize) + 1 | |
| 30 | 42 | } |
| 31 | 43 | }() |
| 32 | 44 | |
| 33 | time.Sleep(time.Second) | |
| 34 | bar3 := p.AddBar(80).PrependElapsed().AppendCompleted() | |
| 35 | wg.Add(1) | |
| 45 | bar3 := p.AddBar(80).AppendETA().PrependFunc(decor) | |
| 36 | 46 | go func() { |
| 37 | defer wg.Done() | |
| 38 | for bar3.Incr() { | |
| 39 | time.Sleep(waitTime) | |
| 47 | blockSize := rand.Intn(maxBlockSize) + 1 | |
| 48 | for i := 0; i < 80; i++ { | |
| 49 | time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) | |
| 50 | bar3.Incr(1) | |
| 51 | blockSize = rand.Intn(maxBlockSize) + 1 | |
| 40 | 52 | } |
| 41 | 53 | }() |
| 42 | 54 | |
| 43 | wg.Wait() | |
| 55 | // time.Sleep(time.Second) | |
| 56 | // p.RemoveBar(bar2) | |
| 57 | ||
| 44 | 58 | p.Stop() |
| 59 | fmt.Println("stop") | |
| 45 | 60 | // p.AddBar(1) // panic: send on closed channnel |
| 46 | 61 | } |
| 26 | 26 | // Width is the width of the progress bars |
| 27 | 27 | // Width int |
| 28 | 28 | |
| 29 | lw *uilive.Writer | |
| 29 | // lw *uilive.Writer | |
| 30 | 30 | |
| 31 | 31 | op chan *operation |
| 32 | 32 | |
| 45 | 45 | // New returns a new progress bar with defaults |
| 46 | 46 | func New() *progress { |
| 47 | 47 | p := &progress{ |
| 48 | out: os.Stdout, | |
| 49 | lw: uilive.New(), | |
| 48 | out: os.Stdout, | |
| 49 | // lw: uilive.New(), | |
| 50 | 50 | op: make(chan *operation), |
| 51 | 51 | interval: make(chan time.Duration), |
| 52 | 52 | wg: new(sync.WaitGroup), |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | // Bypass returns a writer which allows non-buffered data to be written to the underlying output |
| 87 | func (p *progress) Bypass() io.Writer { | |
| 88 | return p.lw.Bypass() | |
| 89 | } | |
| 87 | // func (p *progress) Bypass() io.Writer { | |
| 88 | // return p.lw.Bypass() | |
| 89 | // } | |
| 90 | 90 | |
| 91 | 91 | // Stop stops listening |
| 92 | 92 | func (p *progress) Stop() { |
| 93 | fmt.Fprintln(os.Stderr, "p.Stop") | |
| 93 | 94 | p.wg.Wait() |
| 94 | 95 | close(p.op) |
| 95 | 96 | } |
| 97 | 98 | // server monitors underlying channels and renders any progress bars |
| 98 | 99 | func (p *progress) server() { |
| 99 | 100 | t := time.NewTicker(refreshRate * time.Millisecond) |
| 100 | bars := make([]*Bar, 0) | |
| 101 | p.lw.Out = p.out | |
| 101 | bars := make([]*Bar, 0, 4) | |
| 102 | lw := uilive.New() | |
| 103 | lw.Out = p.out | |
| 102 | 104 | for { |
| 103 | 105 | select { |
| 104 | 106 | case op, ok := <-p.op: |
| 105 | 107 | if !ok { |
| 108 | fmt.Fprintln(os.Stderr, "Sopping bars") | |
| 106 | 109 | for _, b := range bars { |
| 107 | 110 | b.Stop() |
| 108 | 111 | } |
| 109 | 112 | t.Stop() |
| 110 | p.lw.Stop() | |
| 111 | // close(p.interval) | |
| 112 | 113 | return |
| 113 | 114 | } |
| 114 | 115 | switch op.kind { |
| 128 | 129 | } |
| 129 | 130 | case <-t.C: |
| 130 | 131 | for _, b := range bars { |
| 131 | fmt.Fprintln(p.lw, b.String()) | |
| 132 | fmt.Fprintln(lw, b.String()) | |
| 132 | 133 | } |
| 133 | p.lw.Flush() | |
| 134 | // for _, b := range bars { | |
| 135 | // b.flushed() | |
| 136 | // } | |
| 134 | lw.Flush() | |
| 135 | for _, b := range bars { | |
| 136 | b.flushed() | |
| 137 | } | |
| 137 | 138 | case d := <-p.interval: |
| 138 | 139 | t.Stop() |
| 139 | 140 | t = time.NewTicker(d) |