New option mpb.WithWaitGroup
Vladimir Bauer
8 years ago
| 76 | 76 |
own goroutine, therefore adding multiple bars is easy and safe:
|
| 77 | 77 |
|
| 78 | 78 |
```go
|
| 79 | |
p := mpb.New()
|
|
79 |
var wg sync.WaitGroup
|
|
80 |
p := mpb.New(mpb.WithWaitGroup(&wg))
|
| 80 | 81 |
total := 100
|
| 81 | 82 |
numBars := 3
|
| 82 | |
var wg sync.WaitGroup
|
| 83 | 83 |
wg.Add(numBars)
|
| 84 | 84 |
|
| 85 | 85 |
for i := 0; i < numBars; i++ {
|
|
| 96 | 96 |
go func() {
|
| 97 | 97 |
defer wg.Done()
|
| 98 | 98 |
for i := 0; i < total; i++ {
|
| 99 | |
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
| 100 | |
bar.Incr(1)
|
|
99 |
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100)
|
|
100 |
bar.Increment()
|
| 101 | 101 |
}
|
| 102 | 102 |
}()
|
| 103 | 103 |
}
|
| 104 | |
wg.Wait() // Wait for goroutines to finish
|
| 105 | |
p.Stop() // Stop mpb's rendering goroutine
|
|
104 |
// Wait for incr loop goroutines to finish,
|
|
105 |
// and shutdown mpb's rendering goroutine
|
|
106 |
p.Stop()
|
| 106 | 107 |
```
|
| 107 | 108 |
|
| 108 | 109 |

|
| 38 | 38 |
)
|
| 39 | 39 |
|
| 40 | 40 |
for i := 0; i < total; i++ {
|
| 41 | |
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
| 42 | |
bar.Incr(1) // increment progress bar
|
|
41 |
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100)
|
|
42 |
bar.Increment()
|
| 43 | 43 |
}
|
| 44 | 44 |
|
| 45 | 45 |
p.Stop()
|
|
| 50 | 50 |
bar := p.AddBar(100, mpb.AppendDecorators(decor.Percentage(5, 0)))
|
| 51 | 51 |
|
| 52 | 52 |
for bar.InProgress() {
|
| 53 | |
time.Sleep(time.Millisecond * 20)
|
| 54 | |
bar.Incr(1)
|
|
53 |
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100)
|
|
54 |
bar.Increment()
|
| 55 | 55 |
}
|
| 56 | 56 |
}
|
| 21 | 21 |
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
| 22 | 22 |
defer cancel()
|
| 23 | 23 |
|
| 24 | |
p := mpb.New(mpb.WithContext(ctx))
|
| 25 | |
|
| 26 | 24 |
var wg sync.WaitGroup
|
|
25 |
p := mpb.New(
|
|
26 |
mpb.WithWaitGroup(&wg),
|
|
27 |
mpb.WithContext(ctx),
|
|
28 |
)
|
| 27 | 29 |
total := 100
|
| 28 | 30 |
numBars := 3
|
| 29 | 31 |
wg.Add(numBars)
|
|
| 55 | 57 |
}()
|
| 56 | 58 |
}
|
| 57 | 59 |
|
| 58 | |
wg.Wait()
|
| 59 | 60 |
p.Stop()
|
| 60 | 61 |
fmt.Println("stop")
|
| 61 | 62 |
}
|
| 19 | 19 |
url2 := "https://homebrew.bintray.com/bottles/libtiff-4.0.7.sierra.bottle.tar.gz"
|
| 20 | 20 |
|
| 21 | 21 |
var wg sync.WaitGroup
|
| 22 | |
p := mpb.New(mpb.WithWidth(64))
|
|
22 |
p := mpb.New(mpb.WithWaitGroup(&wg))
|
| 23 | 23 |
|
| 24 | 24 |
for i, url := range [...]string{url1, url2} {
|
| 25 | 25 |
wg.Add(1)
|
|
| 27 | 27 |
go download(&wg, p, name, url)
|
| 28 | 28 |
}
|
| 29 | 29 |
|
| 30 | |
wg.Wait()
|
| 31 | 30 |
p.Stop()
|
| 32 | 31 |
fmt.Println("Finished")
|
| 33 | 32 |
}
|
| 10 | 10 |
)
|
| 11 | 11 |
|
| 12 | 12 |
func main() {
|
| 13 | |
p := mpb.New()
|
|
13 |
var wg sync.WaitGroup
|
|
14 |
p := mpb.New(mpb.WithWaitGroup(&wg))
|
| 14 | 15 |
total := 100
|
| 15 | 16 |
numBars := 3
|
| 16 | |
var wg sync.WaitGroup
|
| 17 | 17 |
wg.Add(numBars)
|
| 18 | 18 |
|
| 19 | 19 |
for i := 0; i < numBars; i++ {
|
|
| 30 | 30 |
go func() {
|
| 31 | 31 |
defer wg.Done()
|
| 32 | 32 |
for i := 0; i < total; i++ {
|
| 33 | |
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
| 34 | |
bar.Incr(1)
|
|
33 |
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100)
|
|
34 |
bar.Increment()
|
| 35 | 35 |
}
|
| 36 | 36 |
}()
|
| 37 | 37 |
}
|
| 38 | |
wg.Wait() // Wait for goroutines to finish
|
| 39 | |
p.Stop() // Stop mpb's rendering goroutine
|
|
38 |
// Wait for incr loop goroutines to finish,
|
|
39 |
// and shutdown mpb's rendering goroutine
|
|
40 |
p.Stop()
|
| 40 | 41 |
}
|
| 38 | 38 |
)
|
| 39 | 39 |
|
| 40 | 40 |
for i := 0; i < total; i++ {
|
| 41 | |
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
| 42 | |
bar.Incr(1) // increment progress bar
|
|
41 |
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Second / 100)
|
|
42 |
bar.Increment()
|
| 43 | 43 |
}
|
| 44 | 44 |
|
| 45 | 45 |
p.Stop()
|
| 34 | 34 |
|
| 35 | 35 |
func main() {
|
| 36 | 36 |
|
| 37 | |
p := mpb.New(mpb.WithWidth(64), mpb.WithBeforeRenderFunc(sortByProgressFunc()))
|
| 38 | |
|
|
37 |
var wg sync.WaitGroup
|
|
38 |
p := mpb.New(
|
|
39 |
mpb.WithWaitGroup(&wg),
|
|
40 |
mpb.WithBeforeRenderFunc(sortByProgressFunc()),
|
|
41 |
)
|
| 39 | 42 |
total := 100
|
| 40 | 43 |
numBars := 3
|
| 41 | |
var wg sync.WaitGroup
|
| 42 | 44 |
wg.Add(numBars)
|
| 43 | 45 |
|
| 44 | 46 |
for i := 0; i < numBars; i++ {
|
|
| 66 | 68 |
}()
|
| 67 | 69 |
}
|
| 68 | 70 |
|
| 69 | |
wg.Wait()
|
| 70 | 71 |
p.Stop()
|
| 71 | 72 |
fmt.Println("stop")
|
| 72 | 73 |
}
|
| 2 | 2 |
import (
|
| 3 | 3 |
"io"
|
| 4 | 4 |
"io/ioutil"
|
|
5 |
"sync"
|
| 5 | 6 |
"time"
|
| 6 | 7 |
"unicode/utf8"
|
| 7 | 8 |
|
|
| 11 | 12 |
// ProgressOption is a function option which changes the default behavior of
|
| 12 | 13 |
// progress pool, if passed to mpb.New(...ProgressOption)
|
| 13 | 14 |
type ProgressOption func(*pConf)
|
|
15 |
|
|
16 |
// WithWaitGroup provides means to have a single joint point.
|
|
17 |
// If *sync.WaitGroup is provided, you can safely call just p.Stop()
|
|
18 |
// without calling Wait() on provided *sync.WaitGroup.
|
|
19 |
// Makes sense when there are more than one bar to render.
|
|
20 |
func WithWaitGroup(wg *sync.WaitGroup) ProgressOption {
|
|
21 |
return func(c *pConf) {
|
|
22 |
c.ewg = wg
|
|
23 |
}
|
|
24 |
}
|
| 14 | 25 |
|
| 15 | 26 |
// WithWidth overrides default width 80
|
| 16 | 27 |
func WithWidth(w int) ProgressOption {
|
| 24 | 24 |
width int
|
| 25 | 25 |
format string
|
| 26 | 26 |
rr time.Duration
|
|
27 |
ewg *sync.WaitGroup
|
| 27 | 28 |
cw *cwriter.Writer
|
| 28 | 29 |
ticker *time.Ticker
|
| 29 | 30 |
beforeRender BeforeRender
|
|
| 45 | 46 |
|
| 46 | 47 |
// Progress represents the container that renders Progress bars
|
| 47 | 48 |
type Progress struct {
|
| 48 | |
// WaitGroup for internal rendering sync
|
|
49 |
// wg for internal rendering sync
|
| 49 | 50 |
wg *sync.WaitGroup
|
|
51 |
// External wg
|
|
52 |
ewg *sync.WaitGroup
|
| 50 | 53 |
|
| 51 | 54 |
// quit channel to request p.server to quit
|
| 52 | 55 |
quit chan struct{}
|
|
| 73 | 76 |
}
|
| 74 | 77 |
|
| 75 | 78 |
p := &Progress{
|
|
79 |
ewg: conf.ewg,
|
| 76 | 80 |
wg: new(sync.WaitGroup),
|
| 77 | 81 |
done: make(chan struct{}),
|
| 78 | 82 |
ops: make(chan func(*pConf)),
|
|
| 137 | 141 |
}
|
| 138 | 142 |
}
|
| 139 | 143 |
|
| 140 | |
// Stop shutdowns Progress' goroutine.
|
| 141 | |
// Should be called only after each bar's work done, i.e. bar has reached its
|
| 142 | |
// 100 %. It is NOT for cancelation. Use WithContext or WithCancel for
|
| 143 | |
// cancelation purposes.
|
|
144 |
// Stop is a way to gracefully shutdown mpb's rendering goroutine.
|
|
145 |
// It is NOT for cancelation (use mpb.WithContext for cancelation purposes).
|
|
146 |
// If *sync.WaitGroup has been provided via mpb.WithWaitGroup(), its Wait()
|
|
147 |
// method will be called first.
|
| 144 | 148 |
func (p *Progress) Stop() {
|
|
149 |
if p.ewg != nil {
|
|
150 |
p.ewg.Wait()
|
|
151 |
}
|
| 145 | 152 |
select {
|
| 146 | 153 |
case <-p.quit:
|
| 147 | 154 |
return
|