溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang程序進(jìn)度條如何實(shí)現(xiàn)

發(fā)布時(shí)間:2022-08-29 16:43:15 來源:億速云 閱讀:166 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“golang程序進(jìn)度條如何實(shí)現(xiàn)”,在日常操作中,相信很多人在golang程序進(jìn)度條如何實(shí)現(xiàn)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”golang程序進(jìn)度條如何實(shí)現(xiàn)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

    原理

    終端進(jìn)度條打印的原理是通過輸入\r將光標(biāo)位置移動到當(dāng)前行的行首,重新打印一份進(jìn)度信息。

    如果是使用\n,則光標(biāo)會另起一行打印信息。

    上才藝

    首先從核心功能出發(fā),進(jìn)度條要告訴我的信息有

    • 一共要完成多少任務(wù)

    • 現(xiàn)在完成了多少任務(wù)

    • 到什么時(shí)候才能完成全部任務(wù)

    根據(jù)上面的需求

    畫了個(gè)大概的樣子長這樣 [█████████████████████████]100/100 [eta]16:33:39

    抽象的用戶調(diào)用函數(shù)有3個(gè)

    New()新建進(jìn)度條實(shí)例 Done()推進(jìn)進(jìn)度條進(jìn)展 Finish()完成進(jìn)度條

    是不是和sync.WaitGroup很像。

    調(diào)用代碼

    func main() {
    	bar := progress.New(100)
    	for i := 0; i < 100; i++ {
    		time.Sleep(time.Second / 10)
    		bar.Done(1)
    	}
    	bar.Finish()
    }

    所以根據(jù)用戶調(diào)用需求,首先定義進(jìn)度條結(jié)構(gòu)體。

    type Bar struct {
    	total         int64         // 總進(jìn)度
    	current       int64         // 當(dāng)前進(jìn)度
    	filler        string        // 進(jìn)度填充字符
    	filler_length int64         // 進(jìn)度條長度
    	time_format   string        // 進(jìn)度條時(shí)間格式
    	interval      time.Duration // 打印時(shí)間間隔
    	begin         time.Time     // 任務(wù)開始時(shí)間
    }

    然后根據(jù)用戶調(diào)用的函數(shù),給出函數(shù)實(shí)現(xiàn),當(dāng)然這里面加了一些函數(shù)參數(shù)可選項(xiàng)。

    可以在初始化實(shí)例的時(shí)候自定義一些元素,比如填充字符,比如時(shí)間格式或者是每隔多少時(shí)間刷新一次進(jìn)度條等等。

    // New 新建進(jìn)度條實(shí)例
    func New(total int64, opts ...func(*Bar)) *Bar {
    	bar := &Bar{
    		total:         total,
    		filler:        "█",
    		filler_length: 25,
    		time_format:   "15:04:05", // 2006-01-02T15:04:05
    		interval:      time.Second,
    		begin:         time.Now(),
    	}
    	for _, opt := range opts {
    		opt(bar)
    	}
    	// 定時(shí)打印
    	ticker := time.NewTicker(bar.interval)
    	go func() {
    		for bar.current < bar.total {
    			fmt.Print(bar.get_progress_string())// 打印進(jìn)度
    			<-ticker.C
    		}
    	}()
    	return bar
    }
    // Done 更新完成進(jìn)度
    func (bar *Bar) Done(i int64) {
    	bar.current += i
    }
    // Finish 完成最后進(jìn)度條
    func (bar *Bar) Finish() {
    	fmt.Println(bar.get_progress_string())
    }
    // WithFiller 設(shè)置進(jìn)度條填充字符
    func WithFiller(filler string) func(*Bar) {
    	return func(bar *Bar) {
    		if len(bar.filler) != 0 {
    			bar.filler = filler
    		}
    	}
    }

    那么處理完了用戶怎么使用之后,我們就來開始處理怎么給用戶展示進(jìn)度條效果。

    要想根據(jù)進(jìn)度填充不同的字符比例,先算進(jìn)度百分比,長下面這樣子。

    //get_percent 獲取進(jìn)度百分比,區(qū)間0-100
    func (bar *Bar) get_percent() int64 {
    	return bar.current * 100 / bar.total
    }

    因?yàn)槲覀冞M(jìn)度條并不需要那么精確,所有這里都用的是整數(shù)來處理,更方便一些,不用做各種類型轉(zhuǎn)換。

    那么拿到百分比之后,就能根據(jù)進(jìn)度條總長度來計(jì)算要填充多少個(gè)█。

    接下來算任務(wù)什么時(shí)候完成,這里用的算法是,用當(dāng)前完成了多少個(gè)任務(wù)和花了多少時(shí)間來估算總?cè)蝿?wù)數(shù)的要花費(fèi)多少時(shí)間,得到預(yù)計(jì)什么時(shí)候完成,代碼是這樣子的:

    //get_eta 獲取eta時(shí)間
    func (bar *Bar) get_eta(now time.Time) string {
    	eta := (now.Unix() - bar.begin.Unix()) * 100 / (bar.get_percent() + 1)
    	return bar.begin.Add(time.Second * time.Duration(eta)).Format(bar.time_format)
    }

    最后,我們來處理下需要在控制臺打印的字符串,同時(shí)作為非核心需求,我們還想看批處理操作的速度,所以這里用QPS來表達(dá)我們整個(gè)任務(wù)處理的速度。

    QPS表達(dá)任務(wù)處理速度

    //get_progress_string 獲取打印控制臺字符串
    func (bar *Bar) get_progress_string() string {
    	fills := bar.get_percent() * bar.filler_length / 100
    	for i := int64(0); i < bar.filler_length; i++ {
    		switch {
    		case i < fills:
    			chunks[i] = bar.filler
    		default:
    			chunks[i] = " "
    		}
    	}
    	now := time.Now()
    	eta := bar.get_eta(now)
    	qps := bar.current / (now.Unix() - bar.begin.Unix() + 1)
    	return fmt.Sprintf("\r[%s]%d/%d [eta]%s [qps]%d ", strings.Join(chunks, ""), bar.current, bar.total, eta, qps)
    }

    最終呈現(xiàn)的效果 [█████████████████████████]100/100 [eta]16:33:39 [qps]9 

    當(dāng)然,為了更酷炫一點(diǎn),同時(shí)還引入了emoji字符,能夠根據(jù)字符自適應(yīng)地調(diào)整顯示效果。

    golang程序進(jìn)度條如何實(shí)現(xiàn)

    到此,關(guān)于“golang程序進(jìn)度條如何實(shí)現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI