golang终端应用多进度条显示插件库mpb的使用

golang终端应用多进度条显示插件库mpb的使用

简介

mpb是一个用于在终端应用程序中渲染进度条的Go库。

主要特性

  • 多进度条支持:支持多个进度条同时显示
  • 动态总数:可以在进度条运行时设置总数
  • 动态添加/移除:可以动态添加或移除进度条
  • 取消功能:可以取消整个渲染过程
  • 预定义装饰器:包括已用时间、基于EWMA的ETA、百分比、字节计数器等
  • 装饰器宽度同步:在多个进度条之间同步装饰器的宽度

使用示例

渲染单个进度条

package main

import (
    "math/rand"
    "time"

    "github.com/vbauerster/mpb/v8"
    "github.com/vbauerster/mpb/v8/decor"
)

func main() {
    // 初始化进度容器,自定义宽度
    p := mpb.New(mpb.WithWidth(64))

    total := 100
    name := "Single Bar:"
    // 创建单个进度条,将继承容器的宽度
    bar := p.New(int64(total),
        // 自定义样式的BarFillerBuilder
        mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
        mpb.PrependDecorators(
            // 在右侧显示名称和一个空格
            decor.Name(name, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
            // 在完成时用"done"消息替换ETA装饰器
            decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
        ),
        mpb.AppendDecorators(decor.Percentage()),
    )
    // 模拟工作
    max := 100 * time.Millisecond
    for i := 0; i < total; i++ {
        time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
        bar.Increment()
    }
    // 等待进度条完成并刷新
    p.Wait()
}

渲染多个进度条

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"

    "github.com/vbauerster/mpb/v8"
    "github.com/vbauerster/mpb/v8/decor"
)

func main() {
    var wg sync.WaitGroup
    // 传入的wg将在p.Wait()调用时被计算
    p := mpb.New(mpb.WithWaitGroup(&wg))
    total, numBars := 100, 3
    wg.Add(numBars)

    for i := 0; i < numBars; i++ {
        name := fmt.Sprintf("Bar#%d:", i)
        bar := p.AddBar(int64(total),
            mpb.PrependDecorators(
                // 简单的名称装饰器
                decor.Name(name),
                // decor.DSyncWidth位启用列宽同步
                decor.Percentage(decor.WCSyncSpace),
            ),
            mpb.AppendDecorators(
                // 在完成时用"done"消息替换ETA装饰器
                decor.OnComplete(
                    // EWMA年龄为30的ETA装饰器
                    decor.EwmaETA(decor.ET_STYLE_GO, 30, decor.WCSyncWidth), "done",
                ),
            ),
        )
        // 模拟工作
        go func() {
            defer wg.Done()
            rng := rand.New(rand.NewSource(time.Now().UnixNano()))
            max := 100 * time.Millisecond
            for i := 0; i < total; i++ {
                // start变量仅用于EWMA计算
                // EWMA的度量单位是迭代的持续时间
                start := time.Now()
                time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
                // 需要调用EwmaIncrement来满足ewma装饰器的约定
                bar.EwmaIncrement(time.Since(start))
            }
        }()
    }
    // 等待传入的wg和所有进度条完成并刷新
    p.Wait()
}

动态总数示例

dynTotal

复杂示例

complex

IO示例

io


更多关于golang终端应用多进度条显示插件库mpb的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang终端应用多进度条显示插件库mpb的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用mpb库实现Golang终端多进度条显示

mpb (Multi Progress Bar) 是一个优秀的Golang库,用于在终端应用程序中显示多个进度条。下面我将详细介绍如何使用mpb库。

安装mpb

首先安装mpb库:

go get github.com/vbauerster/mpb/v8

基本使用示例

package main

import (
	"math/rand"
	"time"

	"github.com/vbauerster/mpb/v8"
	"github.com/vbauerster/mpb/v8/decor"
)

func main() {
	// 创建进度条容器
	p := mpb.New(
		mpb.WithWidth(60), // 设置进度条宽度

	// 添加3个进度条
	for i := 0; i < 3; i++ {
		name := "进度条 " + string('A'+i)
		// 创建一个新的进度条
		bar := p.AddBar(100,
			mpb.PrependDecorators(
				// 显示名称
				decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}),
				// 显示百分比
				decor.Percentage(decor.WCSyncSpace),
			),
			mpb.AppendDecorators(
				// 显示预计剩余时间
				decor.EwmaETA(decor.ET_STYLE_GO, 60),
			),
		)

		// 模拟任务进度
		go func() {
			rng := rand.New(rand.NewSource(time.Now().UnixNano()))
			max := 100 * time.Millisecond
			for !bar.Completed() {
				time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
				bar.Increment()
			}
		}()
	}

	// 等待所有进度条完成
	p.Wait()
}

高级功能

1. 自定义进度条样式

bar := p.AddBar(100,
	mpb.BarStyle("[=>-|"),
	mpb.BarFillerClearOnComplete(),
	mpb.PrependDecorators(
		decor.Name("自定义样式: "),
		decor.CountersNoUnit("%d / %d"),
	),
)

2. 动态添加进度条

p := mpb.New()

// 主循环中动态添加进度条
for i := 0; i < 5; i++ {
	time.Sleep(500 * time.Millisecond)
	name := fmt.Sprintf("动态进度条 #%d:", i+1)
	
	bar := p.AddBar(100,
		mpb.PrependDecorators(
			decor.Name(name),
			decor.Percentage(),
		),
	)
	
	go func(b *mpb.Bar) {
		for !b.Completed() {
			time.Sleep(100 * time.Millisecond)
			b.IncrBy(rand.Intn(5) + 1)
		}
	}(bar)
}

p.Wait()

3. 复杂进度条组合

p := mpb.New()

// 主进度条
mainBar := p.AddBar(100,
	mpb.PrependDecorators(
		decor.Name("主任务:"),
		decor.Percentage(),
	),
	mpb.AppendDecorators(
		decor.OnComplete(
			decor.EwmaETA(decor.ET_STYLE_GO, 60), "完成",
		),
	),
)

// 子任务进度条组
subBars := make([]*mpb.Bar, 3)
for i := range subBars {
	subBars[i] = p.AddBar(100,
		mpb.BarQueueAfter(mainBar), // 在主进度条之后显示
		mpb.BarFillerClearOnComplete(),
		mpb.PrependDecorators(
			decor.Name(fmt.Sprintf("  子任务%d:", i+1)),
			decor.CountersNoUnit("%d / %d"),
		),
	)
}

// 模拟任务执行
go func() {
	for i := 0; i < 100; i++ {
		mainBar.Increment()
		time.Sleep(50 * time.Millisecond)
		
		// 每20%更新一次子任务
		if i%20 == 0 {
			for _, b := range subBars {
				b.SetCurrent(0)
				go func(bar *mpb.Bar) {
					for !bar.Completed() {
						time.Sleep(100 * time.Millisecond)
						bar.IncrBy(rand.Intn(10) + 1)
					}
				}(b)
			}
		}
	}
}()

p.Wait()

注意事项

  1. 确保在程序退出前调用p.Wait(),否则可能看不到完整的进度条
  2. 进度条的宽度应考虑终端窗口大小
  3. 对于大量进度条,可以使用mpb.WithRefreshRate调整刷新频率
  4. 可以使用decor.OnComplete在进度条完成后显示自定义消息

mpb库功能强大,支持多种自定义选项,以上示例展示了基本用法和一些高级特性。根据实际需求,您可以进一步探索其文档以了解更多功能。

回到顶部