get rid of start block channel
Vladimir Bauer
7 years ago
| 38 | 38 | |
| 39 | 39 | total := 100 |
| 40 | 40 | name := "Single Bar:" |
| 41 | sbEta := make(chan time.Time) | |
| 42 | 41 | // adding a single bar |
| 43 | 42 | bar := p.AddBar(int64(total), |
| 44 | 43 | mpb.PrependDecorators( |
| 47 | 46 | // replace ETA decorator with "done" message, OnComplete event |
| 48 | 47 | decor.OnComplete( |
| 49 | 48 | // ETA decorator with ewma age of 60, and width reservation of 4 |
| 50 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WC{W: 4}), "done", | |
| 49 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WC{W: 4}), "done", | |
| 51 | 50 | ), |
| 52 | 51 | ), |
| 53 | 52 | mpb.AppendDecorators(decor.Percentage()), |
| 55 | 54 | // simulating some work |
| 56 | 55 | max := 100 * time.Millisecond |
| 57 | 56 | for i := 0; i < total; i++ { |
| 58 | // update start block time, required for ETA calculation | |
| 59 | sbEta <- time.Now() | |
| 57 | start := time.Now() | |
| 60 | 58 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 61 | // increment by 1 (there is bar.IncrBy(int) method, if needed) | |
| 62 | bar.Increment() | |
| 59 | // ewma based decorators require work duration measurement | |
| 60 | bar.IncrBy(1, time.Since(start)) | |
| 63 | 61 | } |
| 64 | 62 | // wait for our bar to complete and flush |
| 65 | 63 | p.Wait() |
| 74 | 72 | |
| 75 | 73 | for i := 0; i < numBars; i++ { |
| 76 | 74 | name := fmt.Sprintf("Bar#%d:", i) |
| 77 | sbEta := make(chan time.Time) | |
| 78 | 75 | bar := p.AddBar(int64(total), |
| 79 | 76 | mpb.PrependDecorators( |
| 80 | 77 | // simple name decorator |
| 86 | 83 | // replace ETA decorator with "done" message, OnComplete event |
| 87 | 84 | decor.OnComplete( |
| 88 | 85 | // ETA decorator with ewma age of 60 |
| 89 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta), "done", | |
| 86 | decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", | |
| 90 | 87 | ), |
| 91 | 88 | ), |
| 92 | 89 | ) |
| 95 | 92 | defer wg.Done() |
| 96 | 93 | max := 100 * time.Millisecond |
| 97 | 94 | for i := 0; i < total; i++ { |
| 98 | sbEta <- time.Now() | |
| 95 | start := time.Now() | |
| 99 | 96 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 100 | bar.Increment() | |
| 97 | // ewma based decorators require work duration measurement | |
| 98 | bar.IncrBy(1, time.Since(start)) | |
| 101 | 99 | } |
| 102 | 100 | }() |
| 103 | 101 | } |
| 121 | 121 | return b |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | // RemoveAllPrependers removes all prepend functions | |
| 124 | // RemoveAllPrependers removes all prepend functions. | |
| 125 | 125 | func (b *Bar) RemoveAllPrependers() { |
| 126 | 126 | select { |
| 127 | 127 | case b.operateState <- func(s *bState) { s.pDecorators = nil }: |
| 129 | 129 | } |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | // RemoveAllAppenders removes all append functions | |
| 132 | // RemoveAllAppenders removes all append functions. | |
| 133 | 133 | func (b *Bar) RemoveAllAppenders() { |
| 134 | 134 | select { |
| 135 | 135 | case b.operateState <- func(s *bState) { s.aDecorators = nil }: |
| 137 | 137 | } |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | // ProxyReader wrapper for io operations, like io.Copy | |
| 141 | // | |
| 142 | // `r` io.Reader to be wrapped | |
| 143 | // | |
| 144 | // `sbChannels` optional start block channels | |
| 145 | func (b *Bar) ProxyReader(r io.Reader, sbChannels ...chan<- time.Time) *Reader { | |
| 140 | // ProxyReader allows progress tracking against provided io.Reader. | |
| 141 | func (b *Bar) ProxyReader(r io.Reader) *Reader { | |
| 146 | 142 | proxyReader := &Reader{ |
| 147 | Reader: r, | |
| 148 | bar: b, | |
| 149 | sbChannels: sbChannels, | |
| 143 | Reader: r, | |
| 144 | bar: b, | |
| 150 | 145 | } |
| 151 | 146 | return proxyReader |
| 152 | 147 | } |
| 153 | 148 | |
| 154 | // NumOfAppenders returns current number of append decorators | |
| 149 | // NumOfAppenders returns current number of append decorators. | |
| 155 | 150 | func (b *Bar) NumOfAppenders() int { |
| 156 | 151 | result := make(chan int) |
| 157 | 152 | select { |
| 162 | 157 | } |
| 163 | 158 | } |
| 164 | 159 | |
| 165 | // NumOfPrependers returns current number of prepend decorators | |
| 160 | // NumOfPrependers returns current number of prepend decorators. | |
| 166 | 161 | func (b *Bar) NumOfPrependers() int { |
| 167 | 162 | result := make(chan int) |
| 168 | 163 | select { |
| 173 | 168 | } |
| 174 | 169 | } |
| 175 | 170 | |
| 176 | // ID returs id of the bar | |
| 171 | // ID returs id of the bar. | |
| 177 | 172 | func (b *Bar) ID() int { |
| 178 | 173 | result := make(chan int) |
| 179 | 174 | select { |
| 208 | 203 | |
| 209 | 204 | // SetTotal sets total dynamically. The final param indicates the very last set, |
| 210 | 205 | // in other words you should set it to true when total is determined. |
| 206 | // After final has been set, IncrBy should be called at least once. | |
| 211 | 207 | func (b *Bar) SetTotal(total int64, final bool) { |
| 212 | 208 | b.operateState <- func(s *bState) { |
| 213 | 209 | if total != 0 { |
| 231 | 227 | } |
| 232 | 228 | |
| 233 | 229 | // IncrBy increments progress bar by amount of n. |
| 234 | func (b *Bar) IncrBy(n int) { | |
| 230 | // wdd is optional work duration i.e. time.Since(start), | |
| 231 | // which expected to be provided, if any ewma based decorator is used. | |
| 232 | func (b *Bar) IncrBy(n int, wdd ...time.Duration) { | |
| 235 | 233 | select { |
| 236 | 234 | case b.operateState <- func(s *bState) { |
| 237 | 235 | s.current += int64(n) |
| 245 | 243 | s.toComplete = true |
| 246 | 244 | } |
| 247 | 245 | for _, ar := range s.amountReceivers { |
| 248 | ar.NextAmount(n) | |
| 246 | ar.NextAmount(n, wdd...) | |
| 249 | 247 | } |
| 250 | 248 | }: |
| 251 | 249 | case <-b.done: |
| 158 | 158 | // |
| 159 | 159 | // `wcc` optional WC config |
| 160 | 160 | // |
| 161 | // pairFormat example: | |
| 161 | // pairFormat example if UnitKB is chosen: | |
| 162 | 162 | // |
| 163 | 163 | // "%.1f / %.1f" = "1.0MB / 12.0MB" or "% .1f / % .1f" = "1.0 MB / 12.0 MB" |
| 164 | 164 | func Counters(unit int, pairFormat string, wcc ...WC) Decorator { |
| 1 | 1 | |
| 2 | 2 | import ( |
| 3 | 3 | "fmt" |
| 4 | "time" | |
| 4 | 5 | "unicode/utf8" |
| 5 | 6 | ) |
| 6 | 7 | |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | 66 | type AmountReceiver interface { |
| 66 | NextAmount(int) | |
| 67 | NextAmount(int, ...time.Duration) | |
| 67 | 68 | } |
| 68 | 69 | |
| 69 | 70 | type ShutdownListener interface { |
| 14 | 14 | // |
| 15 | 15 | // `age` is the previous N samples to average over. |
| 16 | 16 | // |
| 17 | // `sb` is a start block receive channel. It's required by MovingAverage algorithm, | |
| 18 | // therefore result of time.Now() must be sent to this channel on each iteration | |
| 19 | // of a start block, right before the actual job. There is no need to close the channel, | |
| 20 | // as it will be closed automatically on bar completion event. | |
| 21 | // | |
| 22 | 17 | // `wcc` optional WC config |
| 23 | func EwmaETA(style int, age float64, sb chan time.Time, wcc ...WC) Decorator { | |
| 24 | return MovingAverageETA(style, ewma.NewMovingAverage(age), sb, wcc...) | |
| 18 | func EwmaETA(style int, age float64, wcc ...WC) Decorator { | |
| 19 | return MovingAverageETA(style, ewma.NewMovingAverage(age), wcc...) | |
| 25 | 20 | } |
| 26 | 21 | |
| 27 | 22 | // MovingAverageETA decorator relies on MovingAverage implementation to calculate its average. |
| 30 | 25 | // |
| 31 | 26 | // `average` MovingAverage implementation |
| 32 | 27 | // |
| 33 | // `sb` is a start block receive channel. It's required by MovingAverage algorithm, | |
| 34 | // therefore result of time.Now() must be sent to this channel on each iteration | |
| 35 | // of a start block, right before the actual job. There is no need to close the channel, | |
| 36 | // as it will be closed automatically on bar completion event. | |
| 37 | // | |
| 38 | 28 | // `wcc` optional WC config |
| 39 | func MovingAverageETA(style int, average MovingAverage, sb chan time.Time, wcc ...WC) Decorator { | |
| 40 | if sb == nil { | |
| 41 | panic("start block channel must not be nil") | |
| 42 | } | |
| 29 | func MovingAverageETA(style int, average MovingAverage, wcc ...WC) Decorator { | |
| 43 | 30 | var wc WC |
| 44 | 31 | for _, widthConf := range wcc { |
| 45 | 32 | wc = widthConf |
| 46 | 33 | } |
| 47 | 34 | wc.BuildFormat() |
| 48 | 35 | d := &movingAverageETA{ |
| 49 | style: style, | |
| 50 | wc: wc, | |
| 51 | average: average, | |
| 52 | sbReceiver: sb, | |
| 53 | sbStreamer: make(chan time.Time), | |
| 36 | style: style, | |
| 37 | wc: wc, | |
| 38 | average: average, | |
| 54 | 39 | } |
| 55 | go d.serve() | |
| 56 | 40 | return d |
| 57 | 41 | } |
| 58 | 42 | |
| 60 | 44 | style int |
| 61 | 45 | wc WC |
| 62 | 46 | average ewma.MovingAverage |
| 63 | sbReceiver chan time.Time | |
| 64 | sbStreamer chan time.Time | |
| 65 | 47 | onComplete *struct { |
| 66 | 48 | msg string |
| 67 | 49 | wc WC |
| 97 | 79 | return s.wc.FormatMsg(str, widthAccumulator, widthDistributor) |
| 98 | 80 | } |
| 99 | 81 | |
| 100 | func (s *movingAverageETA) NextAmount(n int) { | |
| 101 | sb := <-s.sbStreamer | |
| 102 | lastBlockTime := time.Since(sb) | |
| 103 | lastItemEstimate := float64(lastBlockTime) / float64(n) | |
| 82 | func (s *movingAverageETA) NextAmount(n int, wdd ...time.Duration) { | |
| 83 | var workDuration time.Duration | |
| 84 | for _, wd := range wdd { | |
| 85 | workDuration = wd | |
| 86 | } | |
| 87 | lastItemEstimate := float64(workDuration) / float64(n) | |
| 104 | 88 | s.average.Add(lastItemEstimate) |
| 105 | 89 | } |
| 106 | 90 | |
| 114 | 98 | msg string |
| 115 | 99 | wc WC |
| 116 | 100 | }{msg, wc} |
| 117 | } | |
| 118 | ||
| 119 | func (s *movingAverageETA) Shutdown() { | |
| 120 | close(s.sbReceiver) | |
| 121 | } | |
| 122 | ||
| 123 | func (s *movingAverageETA) serve() { | |
| 124 | for now := range s.sbReceiver { | |
| 125 | s.sbStreamer <- now | |
| 126 | } | |
| 127 | 101 | } |
| 128 | 102 | |
| 129 | 103 | // AverageETA decorator. |
| 126 | 126 | // |
| 127 | 127 | // `average` MovingAverage implementation |
| 128 | 128 | // |
| 129 | // `sb` is a start block receive channel. It's required by MovingAverage algorithm, | |
| 130 | // therefore result of time.Now() must be sent to this channel on each iteration | |
| 131 | // of a start block, right before the actual job. There is no need to close the channel, | |
| 132 | // as it will be closed automatically on bar completion event. | |
| 133 | // | |
| 134 | 129 | // `wcc` optional WC config |
| 135 | 130 | // |
| 136 | // unitFormat example if UnitKiB chosen: | |
| 131 | // unitFormat example if UnitKiB is chosen: | |
| 137 | 132 | // |
| 138 | 133 | // "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s" |
| 139 | func EwmaSpeed(unit int, unitFormat string, age float64, sb chan time.Time, wcc ...WC) Decorator { | |
| 140 | return MovingAverageSpeed(unit, unitFormat, ewma.NewMovingAverage(age), sb, wcc...) | |
| 134 | func EwmaSpeed(unit int, unitFormat string, age float64, wcc ...WC) Decorator { | |
| 135 | return MovingAverageSpeed(unit, unitFormat, ewma.NewMovingAverage(age), wcc...) | |
| 141 | 136 | } |
| 142 | 137 | |
| 143 | 138 | // MovingAverageSpeed decorator relies on MovingAverage implementation to calculate its average. |
| 148 | 143 | // |
| 149 | 144 | // `average` MovingAverage implementation |
| 150 | 145 | // |
| 151 | // `sb` is a start block receive channel. It's required by MovingAverage algorithm, | |
| 152 | // therefore result of time.Now() must be sent to this channel on each iteration | |
| 153 | // of a start block, right before the actual job. There is no need to close the channel, | |
| 154 | // as it will be closed automatically on bar completion event. | |
| 155 | // | |
| 156 | 146 | // `wcc` optional WC config |
| 157 | func MovingAverageSpeed(unit int, unitFormat string, average MovingAverage, sb chan time.Time, wcc ...WC) Decorator { | |
| 158 | if sb == nil { | |
| 159 | panic("start block channel must not be nil") | |
| 160 | } | |
| 147 | func MovingAverageSpeed(unit int, unitFormat string, average MovingAverage, wcc ...WC) Decorator { | |
| 161 | 148 | var wc WC |
| 162 | 149 | for _, widthConf := range wcc { |
| 163 | 150 | wc = widthConf |
| 168 | 155 | unitFormat: unitFormat, |
| 169 | 156 | wc: wc, |
| 170 | 157 | average: average, |
| 171 | sbReceiver: sb, | |
| 172 | sbStreamer: make(chan time.Time), | |
| 173 | } | |
| 174 | go d.serve() | |
| 158 | } | |
| 175 | 159 | return d |
| 176 | 160 | } |
| 177 | 161 | |
| 180 | 164 | unitFormat string |
| 181 | 165 | wc WC |
| 182 | 166 | average ewma.MovingAverage |
| 183 | sbReceiver chan time.Time | |
| 184 | sbStreamer chan time.Time | |
| 185 | 167 | onComplete *struct { |
| 186 | 168 | msg string |
| 187 | 169 | wc WC |
| 205 | 187 | return s.wc.FormatMsg(str, widthAccumulator, widthDistributor) |
| 206 | 188 | } |
| 207 | 189 | |
| 208 | func (s *movingAverageSpeed) NextAmount(n int) { | |
| 209 | sb := <-s.sbStreamer | |
| 210 | speed := float64(n) / time.Since(sb).Seconds() | |
| 190 | func (s *movingAverageSpeed) NextAmount(n int, wdd ...time.Duration) { | |
| 191 | var workDuration time.Duration | |
| 192 | for _, wd := range wdd { | |
| 193 | workDuration = wd | |
| 194 | } | |
| 195 | speed := float64(n) / workDuration.Seconds() | |
| 211 | 196 | s.average.Add(speed) |
| 212 | 197 | } |
| 213 | 198 | |
| 223 | 208 | }{msg, wc} |
| 224 | 209 | } |
| 225 | 210 | |
| 226 | func (s *movingAverageSpeed) Shutdown() { | |
| 227 | close(s.sbReceiver) | |
| 228 | } | |
| 229 | ||
| 230 | func (s *movingAverageSpeed) serve() { | |
| 231 | for now := range s.sbReceiver { | |
| 232 | s.sbStreamer <- now | |
| 233 | } | |
| 234 | } | |
| 235 | ||
| 236 | 211 | // AverageSpeed decorator with dynamic unit measure adjustment. |
| 237 | 212 | // |
| 238 | 213 | // `unit` one of [0|UnitKiB|UnitKB] zero for no unit |
| 241 | 216 | // |
| 242 | 217 | // `wcc` optional WC config |
| 243 | 218 | // |
| 244 | // unitFormat example if UnitKiB chosen: | |
| 219 | // unitFormat example if UnitKiB is chosen: | |
| 245 | 220 | // |
| 246 | 221 | // "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s" |
| 247 | 222 | func AverageSpeed(unit int, unitFormat string, wcc ...WC) Decorator { |
| 22 | 22 | |
| 23 | 23 | total := 100 |
| 24 | 24 | name := "Single Bar:" |
| 25 | sbEta := make(chan time.Time) | |
| 26 | 25 | // adding a single bar |
| 27 | 26 | bar := p.AddBar(int64(total), |
| 28 | 27 | mpb.PrependDecorators( |
| 31 | 30 | // replace ETA decorator with "done" message, OnComplete event |
| 32 | 31 | decor.OnComplete( |
| 33 | 32 | // ETA decorator with ewma age of 60, and width reservation of 4 |
| 34 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WC{W: 4}), "done", | |
| 33 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WC{W: 4}), "done", | |
| 35 | 34 | ), |
| 36 | 35 | ), |
| 37 | 36 | mpb.AppendDecorators(decor.Percentage()), |
| 39 | 38 | // simulating some work |
| 40 | 39 | max := 100 * time.Millisecond |
| 41 | 40 | for i := 0; i < total; i++ { |
| 42 | // update start block time, required for ETA calculation | |
| 43 | sbEta <- time.Now() | |
| 41 | start := time.Now() | |
| 44 | 42 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 45 | // increment by 1 (there is bar.IncrBy(int) method, if needed) | |
| 46 | bar.Increment() | |
| 43 | // ewma based decorators require work duration measurement | |
| 44 | bar.IncrBy(1, time.Since(start)) | |
| 47 | 45 | } |
| 48 | 46 | // wait for our bar to complete and flush |
| 49 | 47 | p.Wait() |
| 31 | 31 | |
| 32 | 32 | for i := 0; i < numBars; i++ { |
| 33 | 33 | name := fmt.Sprintf("Bar#%d:", i) |
| 34 | sbEta := make(chan time.Time) | |
| 35 | 34 | bar := p.AddBar(int64(total), |
| 36 | 35 | mpb.PrependDecorators( |
| 37 | 36 | decor.Name(name), |
| 38 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WCSyncSpace), | |
| 37 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace), | |
| 39 | 38 | ), |
| 40 | 39 | mpb.AppendDecorators( |
| 41 | 40 | decor.Percentage(decor.WC{W: 5}), |
| 46 | 45 | defer wg.Done() |
| 47 | 46 | max := 100 * time.Millisecond |
| 48 | 47 | for !bar.Completed() { |
| 49 | sbEta <- time.Now() | |
| 48 | start := time.Now() | |
| 50 | 49 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 51 | bar.Increment() | |
| 50 | // ewma based decorators require work duration measurement | |
| 51 | bar.IncrBy(1, time.Since(start)) | |
| 52 | 52 | } |
| 53 | 53 | }() |
| 54 | 54 | } |
| 35 | 35 | ), |
| 36 | 36 | mpb.AppendDecorators(decor.Percentage(decor.WC{W: 5})), |
| 37 | 37 | ) |
| 38 | go newTask(wg, b, i+1, nil) | |
| 38 | go newTask(wg, b, i+1) | |
| 39 | 39 | bars = append(bars, b) |
| 40 | 40 | } |
| 41 | 41 | |
| 43 | 43 | doneWg.Add(1) |
| 44 | 44 | i := i |
| 45 | 45 | go func() { |
| 46 | sbEta := make(chan time.Time) | |
| 47 | 46 | task := fmt.Sprintf("Task#%02d:", i) |
| 48 | 47 | job := "installing" |
| 49 | 48 | // preparing delayed bars |
| 54 | 53 | decor.Name(task, decor.WC{W: len(task) + 1, C: decor.DidentRight}), |
| 55 | 54 | decor.OnComplete(decor.Name(job, decor.WCSyncSpaceR), "done!", decor.WCSyncSpaceR), |
| 56 | 55 | decor.OnComplete( |
| 57 | decor.EwmaETA(decor.ET_STYLE_MMSS, 60, sbEta, decor.WCSyncWidth), "", decor.WCSyncSpace, | |
| 56 | decor.EwmaETA(decor.ET_STYLE_MMSS, 60, decor.WCSyncWidth), "", decor.WCSyncSpace, | |
| 58 | 57 | ), |
| 59 | 58 | ), |
| 60 | 59 | mpb.AppendDecorators( |
| 63 | 62 | ) |
| 64 | 63 | // waiting for download to complete, before starting install job |
| 65 | 64 | downloadWgg[i].Wait() |
| 66 | go newTask(doneWg, b, numBars-i, sbEta) | |
| 65 | go newTask(doneWg, b, numBars-i) | |
| 67 | 66 | }() |
| 68 | 67 | } |
| 69 | 68 | |
| 70 | 69 | p.Wait() |
| 71 | 70 | } |
| 72 | 71 | |
| 73 | func newTask(wg *sync.WaitGroup, b *mpb.Bar, incrBy int, sbCh chan<- time.Time) { | |
| 72 | func newTask(wg *sync.WaitGroup, b *mpb.Bar, incrBy int) { | |
| 74 | 73 | defer wg.Done() |
| 75 | 74 | max := 100 * time.Millisecond |
| 76 | 75 | for !b.Completed() { |
| 77 | if sbCh != nil { | |
| 78 | sbCh <- time.Now() | |
| 79 | } | |
| 76 | start := time.Now() | |
| 80 | 77 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 81 | b.IncrBy(incrBy) | |
| 78 | // ewma based decorators require work duration measurement | |
| 79 | b.IncrBy(incrBy, time.Since(start)) | |
| 82 | 80 | } |
| 83 | 81 | } |
| 7 | 7 | "os" |
| 8 | 8 | "path/filepath" |
| 9 | 9 | "sync" |
| 10 | "time" | |
| 11 | 10 | |
| 12 | 11 | "github.com/vbauerster/mpb" |
| 13 | 12 | "github.com/vbauerster/mpb/decor" |
| 57 | 56 | return |
| 58 | 57 | } |
| 59 | 58 | |
| 60 | sbEta := make(chan time.Time) | |
| 61 | 59 | // create bar with appropriate decorators |
| 62 | 60 | bar := p.AddBar(size, mpb.BarPriority(n), |
| 63 | 61 | mpb.PrependDecorators( |
| 65 | 63 | decor.CountersKibiByte("%6.1f / %6.1f", decor.WCSyncWidth), |
| 66 | 64 | ), |
| 67 | 65 | mpb.AppendDecorators( |
| 68 | decor.EwmaETA(decor.ET_STYLE_HHMMSS, 1024*4, sbEta, decor.WCSyncWidth), | |
| 66 | decor.EwmaETA(decor.ET_STYLE_HHMMSS, 1024*4, decor.WCSyncWidth), | |
| 69 | 67 | decor.AverageSpeed(decor.UnitKiB, "% .2f"), |
| 70 | 68 | ), |
| 71 | 69 | ) |
| 72 | 70 | |
| 73 | 71 | // create proxy reader |
| 74 | reader := bar.ProxyReader(resp.Body, sbEta) | |
| 72 | reader := bar.ProxyReader(resp.Body) | |
| 75 | 73 | // and copy from reader |
| 76 | 74 | _, err = io.Copy(dest, reader) |
| 77 | 75 | |
| 42 | 42 | mpb.WithRefreshRate(180*time.Millisecond), |
| 43 | 43 | ) |
| 44 | 44 | |
| 45 | sbEta := make(chan time.Time) | |
| 46 | 45 | bar := p.AddBar(size, |
| 47 | 46 | mpb.PrependDecorators( |
| 48 | 47 | decor.CountersKibiByte("% 6.1f / % 6.1f"), |
| 49 | 48 | ), |
| 50 | 49 | mpb.AppendDecorators( |
| 51 | decor.EwmaETA(decor.ET_STYLE_MMSS, 1024*8, sbEta), | |
| 50 | decor.EwmaETA(decor.ET_STYLE_MMSS, 1024*8), | |
| 52 | 51 | decor.Name(" ] "), |
| 53 | 52 | decor.AverageSpeed(decor.UnitKiB, "% .2f"), |
| 54 | 53 | ), |
| 55 | 54 | ) |
| 56 | 55 | |
| 57 | 56 | // create proxy reader |
| 58 | reader := bar.ProxyReader(resp.Body, sbEta) | |
| 57 | reader := bar.ProxyReader(resp.Body) | |
| 59 | 58 | |
| 60 | 59 | // and copy from reader, ignoring errors |
| 61 | 60 | io.Copy(dest, reader) |
| 28 | 28 | bOption = mpb.BarRemoveOnComplete() |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | sbEta := make(chan time.Time) | |
| 32 | 31 | b := p.AddBar(int64(total), mpb.BarID(i), |
| 33 | 32 | bOption, |
| 34 | 33 | mpb.PrependDecorators( |
| 35 | 34 | decor.Name(name), |
| 36 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WCSyncSpace), | |
| 35 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace), | |
| 37 | 36 | ), |
| 38 | 37 | mpb.AppendDecorators(decor.Percentage()), |
| 39 | 38 | ) |
| 41 | 40 | defer wg.Done() |
| 42 | 41 | max := 100 * time.Millisecond |
| 43 | 42 | for i := 0; i < total; i++ { |
| 44 | sbEta <- time.Now() | |
| 43 | start := time.Now() | |
| 45 | 44 | if b.ID() == 2 && i == 42 { |
| 46 | 45 | p.Abort(b) |
| 47 | 46 | return |
| 48 | 47 | } |
| 49 | 48 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 50 | b.Increment() | |
| 49 | // ewma based decorators require work duration measurement | |
| 50 | b.IncrBy(1, time.Since(start)) | |
| 51 | 51 | } |
| 52 | 52 | }() |
| 53 | 53 | } |
| 21 | 21 | |
| 22 | 22 | for i := 0; i < numBars; i++ { |
| 23 | 23 | name := fmt.Sprintf("Bar#%d:", i) |
| 24 | sbEta := make(chan time.Time) | |
| 25 | 24 | bar := p.AddBar(int64(total), |
| 26 | 25 | mpb.PrependDecorators( |
| 27 | 26 | // simple name decorator |
| 33 | 32 | // replace ETA decorator with "done" message, OnComplete event |
| 34 | 33 | decor.OnComplete( |
| 35 | 34 | // ETA decorator with ewma age of 60 |
| 36 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta), "done", | |
| 35 | decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", | |
| 37 | 36 | ), |
| 38 | 37 | ), |
| 39 | 38 | ) |
| 42 | 41 | defer wg.Done() |
| 43 | 42 | max := 100 * time.Millisecond |
| 44 | 43 | for i := 0; i < total; i++ { |
| 45 | sbEta <- time.Now() | |
| 44 | start := time.Now() | |
| 46 | 45 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 47 | bar.Increment() | |
| 46 | // ewma based decorators require work duration measurement | |
| 47 | bar.IncrBy(1, time.Since(start)) | |
| 48 | 48 | } |
| 49 | 49 | }() |
| 50 | 50 | } |
| 19 | 19 | |
| 20 | 20 | total := 100 |
| 21 | 21 | name := "Single Bar:" |
| 22 | sbEta := make(chan time.Time) | |
| 23 | 22 | // adding a single bar |
| 24 | 23 | bar := p.AddBar(int64(total), |
| 25 | 24 | mpb.PrependDecorators( |
| 28 | 27 | // replace ETA decorator with "done" message, OnComplete event |
| 29 | 28 | decor.OnComplete( |
| 30 | 29 | // ETA decorator with ewma age of 60, and width reservation of 4 |
| 31 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WC{W: 4}), "done", | |
| 30 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WC{W: 4}), "done", | |
| 32 | 31 | ), |
| 33 | 32 | ), |
| 34 | 33 | mpb.AppendDecorators(decor.Percentage()), |
| 36 | 35 | // simulating some work |
| 37 | 36 | max := 100 * time.Millisecond |
| 38 | 37 | for i := 0; i < total; i++ { |
| 39 | // update start block time, required for ETA calculation | |
| 40 | sbEta <- time.Now() | |
| 38 | start := time.Now() | |
| 41 | 39 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 42 | // increment by 1 (there is bar.IncrBy(int) method, if needed) | |
| 43 | bar.Increment() | |
| 40 | // ewma based decorators require work duration measurement | |
| 41 | bar.IncrBy(1, time.Since(start)) | |
| 44 | 42 | } |
| 45 | 43 | // wait for our bar to complete and flush |
| 46 | 44 | p.Wait() |
| 25 | 25 | if i != 1 { |
| 26 | 26 | name = fmt.Sprintf("Bar#%d:", i) |
| 27 | 27 | } |
| 28 | sbEta := make(chan time.Time) | |
| 29 | 28 | b := p.AddBar(int64(total), |
| 30 | 29 | mpb.PrependDecorators( |
| 31 | 30 | decor.Name(name, decor.WCSyncWidth), |
| 32 | 31 | decor.CountersNoUnit("%d / %d", decor.WCSyncSpace), |
| 33 | 32 | ), |
| 34 | 33 | mpb.AppendDecorators( |
| 35 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WC{W: 3}), | |
| 34 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WC{W: 3}), | |
| 36 | 35 | ), |
| 37 | 36 | ) |
| 38 | 37 | go func() { |
| 39 | 38 | defer wg.Done() |
| 40 | 39 | max := 100 * time.Millisecond |
| 41 | 40 | for i := 0; i < total; i++ { |
| 42 | sbEta <- time.Now() | |
| 41 | start := time.Now() | |
| 43 | 42 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 44 | 43 | if i&1 == 1 { |
| 45 | 44 | priority := total - int(b.Current()) |
| 46 | 45 | p.UpdateBarPriority(b, priority) |
| 47 | 46 | } |
| 48 | b.Increment() | |
| 47 | // ewma based decorators require work duration measurement | |
| 48 | b.IncrBy(1, time.Since(start)) | |
| 49 | 49 | } |
| 50 | 50 | }() |
| 51 | 51 | } |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | func main() { |
| 21 | ||
| 22 | 21 | var wg sync.WaitGroup |
| 23 | 22 | p := mpb.New(mpb.WithWaitGroup(&wg)) |
| 24 | 23 | wg.Add(totalBars) |
| 26 | 25 | for i := 0; i < totalBars; i++ { |
| 27 | 26 | name := fmt.Sprintf("Bar#%02d: ", i) |
| 28 | 27 | total := rand.Intn(320) + 10 |
| 29 | sbEta := make(chan time.Time) | |
| 30 | 28 | bar := p.AddBar(int64(total), |
| 31 | 29 | mpb.PrependDecorators( |
| 32 | 30 | decor.Name(name), |
| 33 | decor.EwmaETA(decor.ET_STYLE_GO, 60, sbEta, decor.WCSyncSpace), | |
| 31 | decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace), | |
| 34 | 32 | ), |
| 35 | 33 | mpb.AppendDecorators( |
| 36 | 34 | decor.Percentage(decor.WC{W: 5}), |
| 41 | 39 | defer wg.Done() |
| 42 | 40 | max := 100 * time.Millisecond |
| 43 | 41 | for !bar.Completed() { |
| 44 | sbEta <- time.Now() | |
| 42 | start := time.Now() | |
| 45 | 43 | time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) |
| 46 | bar.Increment() | |
| 44 | // ewma based decorators require work duration measurement | |
| 45 | bar.IncrBy(1, time.Since(start)) | |
| 47 | 46 | } |
| 48 | 47 | }() |
| 49 | 48 | } |
| 7 | 7 | // Reader is io.Reader wrapper, for proxy read bytes |
| 8 | 8 | type Reader struct { |
| 9 | 9 | io.Reader |
| 10 | bar *Bar | |
| 11 | sbChannels []chan<- time.Time | |
| 10 | bar *Bar | |
| 12 | 11 | } |
| 13 | 12 | |
| 14 | 13 | func (r *Reader) Read(p []byte) (int, error) { |
| 15 | select { | |
| 16 | case <-r.bar.done: | |
| 17 | default: | |
| 18 | for _, ch := range r.sbChannels { | |
| 19 | ch <- time.Now() | |
| 20 | } | |
| 21 | } | |
| 14 | start := time.Now() | |
| 22 | 15 | n, err := r.Reader.Read(p) |
| 23 | r.bar.IncrBy(n) | |
| 16 | r.bar.IncrBy(n, time.Since(start)) | |
| 24 | 17 | return n, err |
| 25 | 18 | } |
| 26 | 19 |