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

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

如何解決Go通道死鎖?

如何解決Go通道死鎖?

Go
繁星點點滴滴 2023-07-26 15:45:22
我正在學習Go編程語言,最近我遇到一個問題,我嘗試了很多方法來運行我的代碼,但我無法正確運行。我怎樣才能改變我的程序來做到這一點?package mainimport (    "fmt"    "sync")type Task struct {    Id       int    Callback chan int}func main() {    var wg sync.WaitGroup    subTask := make([]Task, 100)    for i := 0; i < 100; i++ {        go func(i int) {            task := Task{                Id:       i,                Callback: make(chan int, 1),            }            task.Callback <- i            subTask = append(subTask, task)        }(i)    }    for _, v := range subTask {        wg.Add(1)        go func(v Task) {            defer wg.Done()            x := <-v.Callback            fmt.Printf("%d ", x)        }(v)    }    wg.Wait()}
查看完整描述

4 回答

?
慕桂英3389331

TA貢獻2036條經驗 獲得超8個贊

正在進行一場數據競賽subTask。subTask任務初始化 goroutine在不同步的情況下讀取和寫入變量。


該程序的目的是創建并初始化一個包含 100 個Task值的切片,但它創建了一個包含 100 個零值的切片Task,并附加了 100 個以上的初始化Task值(忽略剛才提到的數據競爭問題)。


通過將任務分配給切片元素來修復這兩個問題:


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

? ? go func(i int) {

? ? ? ? task := Task{

? ? ? ? ? ? Id:? ? ? ?i,

? ? ? ? ? ? Callback: make(chan int, 1),

? ? ? ? }

? ? ? ? task.Callback <- i

? ? ? ? subTask[i] = task

? ? }(i)

}

元素上存在數據競爭subTask。無法保證任務初始化 Goroutines 在主 Goroutine 覆蓋這些元素之前完成對元素的寫入。通過使用等待組來協調初始化 Goroutine 和主 Goroutine 的完成來修復:


subTask := make([]Task, 100)

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

? ? wg.Add(1)

? ? go func(i int) {

? ? ? ? task := Task{

? ? ? ? ? ? Id:? ? ? ?i,

? ? ? ? ? ? Callback: make(chan int, 1),

? ? ? ? }

? ? ? ? task.Callback <- i

? ? ? ? subTask[i] = task

? ? ? ? wg.Done()

? ? }(i)

}

wg.Wait()


競爭檢測器報告上述兩種數據競爭。

如果問題中的代碼是實際代碼,而不是用于提出問題的最小示例,則根本不需要 goroutine。


查看完整回答
反對 回復 2023-07-26
?
肥皂起泡泡

TA貢獻1829條經驗 獲得超6個贊

如果通道為零,則<-c來自 c 的接收將永遠阻塞。因此出現死鎖。通道可能為 nil 的原因是,在執行 goroutine 接收時,第一個 for 循環中的其中一個 goroutine 可能尚未執行。

因此,如果您假設第一個 for 循環中的所有 goroutine 在第二個 for 循環開始之前執行,那么您的代碼將會正常工作。

添加睡眠可以讓您看到差異,但您實際上應該解決這個問題。

可能出現問題的另一件事是, subTask := make([]Task, 100)此語句在切片中創建 100 個空任務 obj,并追加添加更多內容,因此長度最終會增長到 200。

https://play.golang.org/p/4bZDJ2zvKdF


查看完整回答
反對 回復 2023-07-26
?
慕俠2389804

TA貢獻1719條經驗 獲得超6個贊

您可以考慮一串任務,而不是一部分任務。


我認為這保留了您創建 100 個獨立讀寫頻道的原始想法。它還避免了數據競爭。


func main() {

    subTasks := make(chan Task)

    var wg sync.WaitGroup

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

        wg.Add(1)

        go func(i int) {

            defer wg.Done()

            task := Task{i, make(chan int)}

            subTasks <- task

            task.Callback <- i

        }(i)

    }


    go func() {

        wg.Wait()

        close(subTasks)

    }()


    for v := range subTasks {

        go func(v Task) {

            fmt.Println(<-v.Callback)

        }(v)

    }

}

在操場上奔跑


查看完整回答
反對 回復 2023-07-26
?
HUH函數

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

一個問題是您要追加到切片而不是更新現有的切片項。而且你不需要緩沖的chan。


func main() {

    subTask := make([]Task, 100)

    for i := range subTask {

        go func(i int) {

            subTask[i] = Task{i, make(chan int)}

            subTask[i].Callback <- i

        }(i)

    }


    var wg sync.WaitGroup

    wg.Add(len(subTask))

    for _, v := range subTask {

        go func(v Task) {

            defer wg.Done()

            fmt.Println(<-v.Callback)

        }(v)

    }

    wg.Wait()

}


查看完整回答
反對 回復 2023-07-26
  • 4 回答
  • 0 關注
  • 205 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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