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

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

無法同時使用 goroutines 來查找最大值,直到上下文被取消

無法同時使用 goroutines 來查找最大值,直到上下文被取消

Go
喵喵時光機 2022-09-05 17:44:54
我已經成功地做了一個同步解決方案,沒有對調用的干擾。findMaxcomputepackage mainimport (    "context"    "fmt"    "math/rand"    "time")func findMax(ctx context.Context, concurrency int) uint64 {    var (        max uint64 = 0        num uint64 = 0    )    for i := 0; i < concurrency; i++ {        num = compute()        if num > max {            max = num        }    }    return max}func compute() uint64 {    // NOTE: This is a MOCK implementation of the blocking operation.        time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond)    return rand.Uint64()}func main() {    maxDuration := 2 * time.Second    concurrency := 10    ctx, cancel := context.WithTimeout(context.Background(), maxDuration)    defer cancel()    max := findMax(ctx, concurrency)    fmt.Println(max)}https://play.golang.org/p/lYXRNTDtNCI當我嘗試使用 goroutines 來重復調用函數時使用盡可能多的 goroutines,直到上下文被調用方函數取消。我每次都得到0,而不是灌漿計算函數調用的預期最大值。我嘗試了不同的方法來做到這一點,并且大部分時間都陷入僵局。findMaxcomputectxmainpackage mainimport (    "context"    "fmt"    "math/rand"    "time")func findMax(ctx context.Context, concurrency int) uint64 {    var (        max uint64 = 0        num uint64 = 0    )    for i := 0; i < concurrency; i++ {        select {        case <- ctx.Done():            return max        default:            go func() {                num = compute()                if num > max {                    max = num                }            }()        }    }    return max}func compute() uint64 {    // NOTE: This is a MOCK implementation of the blocking operation.        time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond)    return rand.Uint64()}func main() {    maxDuration := 2 * time.Second    concurrency := 10    ctx, cancel := context.WithTimeout(context.Background(), maxDuration)    defer cancel()    max := findMax(ctx, concurrency)    fmt.Println(max)}https://play.golang.org/p/3fFFq2xlXAE
查看完整描述

1 回答

?
元芳怎么了

TA貢獻1798條經驗 獲得超7個贊

您的程序存在多個問題:

  1. 您正在生成多個對共享變量進行操作的goroutine,即,并導致數據競爭,因為它們不受保護(例如,受Mutex保護)。maxnum

  2. 這里由每個 worker goroutine 修改,但它應該是 worker 的本地,否則計算的數據可能會丟失(例如,一個 worker goroutine 計算了一個結果并將其存儲在 num 中,但緊隨其后,第二個 worker 計算并替換了 num 的值)。num

 num = compute // Should be "num := compute"
  1. 您不會等待每個 goroutine 完成計算,這可能會導致不正確的結果,因為即使上下文未取消,也不會考慮每個工作線程計算。使用 或 渠道來解決此問題。sync.WaitGroup

下面是一個示例程序,可解決代碼中的大多數問題:

package main


import (

    "context"

    "fmt"

    "math/rand"

    "sync"

    "time"

)


type result struct {

    sync.RWMutex

    max uint64

}


func findMax(ctx context.Context, workers int) uint64 {

    var (

        res = result{}

        wg  = sync.WaitGroup{}

    )


    for i := 0; i < workers; i++ {

        select {

        case <-ctx.Done():

            // RLock to read res.max

            res.RLock()

            ret := res.max

            res.RUnlock()

            return ret

        default:

            wg.Add(1)

            go func() {

                defer wg.Done()

                num := compute()


                // Lock so that read from res.max and write

                // to res.max is safe. Else, data race could

                // occur.

                res.Lock()

                if num > res.max {

                    res.max = num

                }

                res.Unlock()

            }()

        }

    }


    // Wait for all the goroutine to finish work i.e., all

    // workers are done computing and updating the max.

    wg.Wait()


    return res.max

}


func compute() uint64 {

    rnd := rand.Int63n(100)

    time.Sleep(time.Duration(rnd) * time.Millisecond)

    return rand.Uint64()

}


func main() {

    maxDuration := 2 * time.Second

    concurrency := 10


    ctx, cancel := context.WithTimeout(context.Background(), maxDuration)

    defer cancel()


    fmt.Println(findMax(ctx, concurrency))

}

正如@Brits在注釋中指出的那樣,當上下文被取消時,請確保停止那些工作線程goroutines以停止處理(如果可能的話),因為它不再需要了。


查看完整回答
反對 回復 2022-09-05
  • 1 回答
  • 0 關注
  • 98 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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