第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

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

用于取消機(jī)上例程的 golang 設(shè)計模式

用于取消機(jī)上例程的 golang 設(shè)計模式

Go
米琪卡哇伊 2023-06-19 15:31:12
我是一個 golang 新手,正試圖了解這個問題的正確設(shè)計模式。我當(dāng)前的解決方案似乎非常冗長,而且我不確定更好的方法是什么。我正在嘗試設(shè)計一個系統(tǒng):執(zhí)行 N 個協(xié)程一旦可用,就返回每個 goroutine 的結(jié)果如果一個 goroutine 返回一個特定的值,它應(yīng)該殺死其他 goroutines 將取消。目標(biāo):我想啟動多個 goroutine,但如果一個例程返回特定結(jié)果,我想取消這些例程。我試圖了解我的代碼是否超級“臭”,或者這是否是規(guī)定的做事方式。我仍然沒有很好的感覺,所以任何幫助將不勝感激。這是我寫的:package mainimport (    "context"    "fmt"    "time")func main() {    ctx := context.Background()    ctx, cancel := context.WithCancel(ctx)    fooCheck := make(chan bool)    barCheck := make(chan bool)    go foo(ctx, 3000, fooCheck)    go bar(ctx, 5000, barCheck)    for fooCheck != nil ||        barCheck != nil {        select {        case res, ok := <-fooCheck:            if !ok {                fooCheck = nil                continue            }            if res == false {                cancel()            }            fmt.Printf("result of foocheck: %t\n", res)        case res, ok := <-barCheck:            if !ok {                barCheck = nil                continue            }            fmt.Printf("result of barcheck: %t\n", res)        }    }    fmt.Printf("here we are at the end of the loop, ready to do some more processing...")}func foo(ctx context.Context, pretendWorkTime int, in chan<- bool) {    fmt.Printf("simulate doing foo work and pass ctx down to cancel down the calltree\n")    time.Sleep(time.Millisecond * time.Duration(pretendWorkTime))    select {    case <-ctx.Done():        fmt.Printf("\n\nWe cancelled this operation!\n\n")        break    default:        fmt.Printf("we have done some foo work!\n")        in <- false    }    close(in)}func bar(ctx context.Context, pretendWorkTime int, in chan<- bool) {    fmt.Printf("simulate doing bar work and pass ctx down to cancel down the calltree\n")    time.Sleep(time.Millisecond * time.Duration(pretendWorkTime))    select {    case <-ctx.Done():        fmt.Printf("\n\nWe cancelled the bar operation!\n\n")        break    default:        fmt.Printf("we have done some bar work!\n")        in <- true    }    close(in)}輸出按預(yù)期工作,但恐怕我正在做一些決定,稍后會吹走我的腳。
查看完整描述

2 回答

?
嚕嚕噠

TA貢獻(xiàn)1784條經(jīng)驗(yàn) 獲得超7個贊

我會使用單一渠道來傳達(dá)結(jié)果,因此收集結(jié)果要容易得多,而且它會根據(jù)其性質(zhì)自動“縮放”。如果您需要識別結(jié)果的來源,只需使用包含來源的包裝器即可。是這樣的:


type Result struct {

? ? ID? ? ?string

? ? Result bool

}

為了模擬“真實(shí)”工作,工作人員應(yīng)該使用一個循環(huán)以迭代方式完成他們的工作,并且在每次迭代中他們應(yīng)該檢查取消信號。是這樣的:


func foo(ctx context.Context, pretendWorkMs int, resch chan<- Result) {

? ? log.Printf("foo started...")

? ? for i := 0; i < pretendWorkMs; i++ {

? ? ? ? time.Sleep(time.Millisecond)

? ? ? ? select {

? ? ? ? case <-ctx.Done():

? ? ? ? ? ? log.Printf("foo terminated.")

? ? ? ? ? ? return

? ? ? ? default:

? ? ? ? }

? ? }

? ? log.Printf("foo finished")

? ? resch <- Result{ID: "foo", Result: false}

}

在我們的示例中, thebar()是相同的,只是將所有foo單詞替換為bar。


現(xiàn)在執(zhí)行作業(yè)并提前終止其余作業(yè)(如果確實(shí)符合我們的預(yù)期),如下所示:


ctx, cancel := context.WithCancel(context.Background())

defer cancel()


resch := make(chan Result, 2)


log.Println("Kicking off workers...")

go foo(ctx, 3000, resch)

go bar(ctx, 5000, resch)


for i := 0; i < cap(resch); i++ {

? ? result := <-resch

? ? log.Printf("Result of %s: %v", result.ID, result.Result)

? ? if !result.Result {

? ? ? ? cancel()

? ? ? ? break

? ? }

}

log.Println("Done.")

運(yùn)行此應(yīng)用程序?qū)⑤敵觯ㄔ贕o Playground上嘗試):


2009/11/10 23:00:00 Kicking off workers...

2009/11/10 23:00:00 bar started...

2009/11/10 23:00:00 foo started...

2009/11/10 23:00:03 foo finished

2009/11/10 23:00:03 Result of foo: false

2009/11/10 23:00:03 Done.

有些事情要注意。如果我們由于意外結(jié)果提前終止,cancel()函數(shù)將被調(diào)用,我們從循環(huán)中跳出??赡芷溆嗟墓ぷ魅藛T也同時完成他們的工作并發(fā)送他們的結(jié)果,這不會成為問題,因?yàn)槲覀兪褂昧司彌_通道,所以他們的發(fā)送不會阻塞并且他們會正確結(jié)束。此外,如果他們沒有同時完成,他們會檢查ctx.Done()他們的循環(huán),并且他們提前終止,所以 goroutines 被很好地清理了。


另請注意,上面代碼的輸出不打印bar terminated。這是因?yàn)?code>main()函數(shù)在循環(huán)后立即終止,一旦main()函數(shù)結(jié)束,它不會等待其他非maingoroutines 完成。如果應(yīng)用程序不會立即終止,我們也會看到該行被打印出來。time.Sleep()如果我們在末尾添加一個main()


log.Println("Done.")

time.Sleep(3 * time.Millisecond)

輸出將是(在Go Playground上嘗試):


2009/11/10 23:00:00 Kicking off workers...

2009/11/10 23:00:00 bar started...

2009/11/10 23:00:00 foo started...

2009/11/10 23:00:03 foo finished

2009/11/10 23:00:03 Result of foo: false

2009/11/10 23:00:03 Done.

2009/11/10 23:00:03 bar terminated.

現(xiàn)在,如果您必須等待所有工作人員“正?!被颉疤崆啊苯Y(jié)束才能繼續(xù),您可以通過多種方式實(shí)現(xiàn)。


一種方法是使用sync.WaitGroup.?另一種方法是讓每個工作人員發(fā)送一個Result無論他們?nèi)绾谓Y(jié)束,并且Result可以包含終止條件,例如normalor?aborted。goroutinemain()可以繼續(xù)接收循環(huán),直到它n從 接收到值resch。如果選擇此解決方案,您必須確保每個工作人員發(fā)送一個值(即使發(fā)生恐慌)以main()在這種情況下(例如使用 using?defer)不阻塞。



查看完整回答
反對 回復(fù) 2023-06-19
?
米脂

TA貢獻(xiàn)1836條經(jīng)驗(yàn) 獲得超3個贊

我將針對您所說的內(nèi)容分享最簡單的模式。您可以將其擴(kuò)展到更復(fù)雜的場景。


func doStuff() {

    // This can be a chan of anything.

    msgCh := make(chan string)


    // This is how you tell your go-routine(s) to stop, by closing this chan.

    quitCh := make(chan struct{})

    defer close(quitCh)


    // Start all go routines.

    for whileStart() {

        go func() {

            // Do w/e you need inside of your go-routine.


            // Write back the result.

            select {

            case msgCh <- "my message":

                // If we got here then the chan is open.

            case <-quitCh:

                // If we got here then the quit chan was closed.

            }

        }()

    }


    // Wait for all go routines.

    for whileWait() {

        // Block until a msg comes back.

        msg := <-msgCh

        // If you found what you want.

        if msg == stopMe {

            // It's safe to return because of the defer earlier.

            return

        }

    }

}


查看完整回答
反對 回復(fù) 2023-06-19
  • 2 回答
  • 0 關(guān)注
  • 149 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號