亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

跟蹤長時間運行任務的進度 - 正確方法

跟蹤長時間運行任務的進度 - 正確方法

Go
天涯盡頭無女友 2022-12-26 10:49:01
我想跟蹤一些長時間運行的進程的執行并顯示用戶完成百分比和錯誤(如果有)。如果這是一個長時間運行的過程,那么很容易——您可以為進度(百分比)和錯誤創建渠道。當我們有 X 個長時間運行的進程時,實現這種邏輯的正確方法是什么?下面是一段有效的代碼,但我不太喜歡它的實現方式。我創建了一個結構ProgressTracker,將Url(作為一個字段)Error,Progress 作為通道。我將其保存ProgressTracker在一個切片中,一旦我提交了所有任務,我就會遍歷切片ProgressTracker并收聽每個trackerin的頻道ProgressTracker。一旦提交的請求數 == 收到的響應數 - 退出循環。它是 Go 慣用的解決方案嗎?作為通道傳遞給函數會更容易ProgressTracker,但我不知道在這種情況下如何正確發送“進度”、“錯誤”和“完成”事件。代碼如下,Go playground 中也有同樣的代碼:https ://go.dev/play/p/f3hXJsZR9WV
查看完整描述

2 回答

?
Helenr

TA貢獻1780條經驗 獲得超4個贊

你陷入僵局是因為你繼續select反對那些沒有違約的跟蹤器。您的內部for循環每次都會迭代所有跟蹤器,其中包括已完成且永遠不會發送另一條消息的跟蹤器。解決這個問題的最簡單方法是 empty default,這也會使它們在現實生活中表現得更好,因為它們并非都以相同的速度運行,但它確實會將其變成一個會消耗更多 CPU 的緊密循環。

WaitGroup什么都不做;你正在調用Wait一個 goroutine,但當它返回時什么也不做,而且你永遠不會調用Done它正在跟蹤的 goroutine,所以它永遠不會返回。相反,您單獨跟蹤Complete收到的消息數量并使用它而不是 WaitGroup;目前尚不清楚為什么以這種方式實施。

修復兩者可解決所述問題:https ://go.dev/play/p/do0g9jrX0mY

但是,這可能不是正確的方法。不可能用一個人為的例子來說明正確的方法是什么;如果這個例子就是它需要做的全部,你不需要任何邏輯,你可以把你的打印語句放在工作人員中,只使用一個等待組而不使用任何通道就可以完成它。假設你實際上正在對結果做某事,你可能想要一個單一的Completed通道和一個Error由所有工作人員共享的單一通道,并且可能需要一個完全不同的機制來跟蹤進度,比如你可以從中讀取的原子 int/float想知道目前的進展。那么你不需要嵌套循環的東西,你只需要一個循環select從共享頻道讀取消息。這完全取決于打算使用此代碼的上下文。


查看完整回答
反對 回復 2022-12-26
?
RISEBY

TA貢獻1856條經驗 獲得超5個贊

我想出了這種方法,它適用于我的需要:


package main


import (

    "errors"

    "fmt"

    "strings"

    "sync"

    "time"

)


type ProgressTracker struct {

    Progress  int

    Error     error

    Completed bool

    Url       string

}


/**

This method sleeps for 1 second and sends progress (in %) in each iteration to Progress channel

For .net sites on 3rd iteration fail with error

When everything is completed, send a message to Complete channel

*/

func work(url string, tracker chan ProgressTracker) {

    var internalTracker = ProgressTracker{

        Url: url,

    }

    tracker <- internalTracker

    fmt.Printf("processing url %s\n", url)

    for i := 1; i <= 5; i++ {

        if url == "google.com" {

            time.Sleep(time.Second * 3)

        }

        time.Sleep(time.Second)

        if i == 3 && strings.HasSuffix(url, ".net") {

            internalTracker.Error = errors.New("error for .net sites")

            internalTracker.Completed = true

            tracker <- internalTracker

            return

        }

        progress := 20 * i

        internalTracker.Progress = progress

        internalTracker.Completed = false

        tracker <- internalTracker

    }

    internalTracker.Completed = true

    tracker <- internalTracker

}


func main() {

    var urls = []string{"google.com", "youtube.com", "someurl.net"}

    var tracker = make(chan ProgressTracker, len(urls))

    var wg sync.WaitGroup

    wg.Add(len(urls))


    for _, url := range urls {

        go func(workUrl string) {

            defer wg.Done()

            work(workUrl, tracker)

        }(url)

    }


    go func() {

        wg.Wait()

        close(tracker)

        fmt.Printf("After wg wait")

    }()


    var completed = 0


    for completed < len(urls) {

        select {

        case t := <-tracker:

            if t.Completed {

                fmt.Printf("Processing for %s is completed!\n", t.Url)

                completed = completed + 1

            } else {

                fmt.Printf("Processing for %s is in progress: %d\n", t.Url, t.Progress)

            }

            if t.Error != nil {

                fmt.Printf("Url %s has errors %s\n", t.Url, t.Error)

            }

        }


    }

}

在這里,我ProgressTracker作為通道傳遞(中的字段ProgressTracker被聲明為簡單字段,而不是通道)并且在來自工作函數的每個事件上返回正在發生的事情的完整狀態(如果進度增加 - 設置新值并將結構返回通道,如果發生錯誤 - 設置錯誤并返回結構等)。


查看完整回答
反對 回復 2022-12-26
  • 2 回答
  • 0 關注
  • 114 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號