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

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

如何修復2個通道互相死鎖

如何修復2個通道互相死鎖

Go
森林海 2022-04-26 14:13:43
我有這段 Go 代碼。我需要具備這種能力:在一個地方寫入通道,并在另一個地方讀出它們(反之亦然):package mainimport "fmt"var ch1=make(chan int)var ch2=make(chan int)func f1() {    select {    case <- ch1:fmt.Println("ch1")    default: fmt.Println("default")    }}func f2() {    select {    case <- ch2:fmt.Println("ch2")    default: fmt.Println("default")    }}func main() {    go f1()    go f2()    ch1<-1    ch2<-2}它總是這樣打?。篸efaultch1fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:main.main()    /tmp/sandbox970110849/prog.go:22 +0xa0此外,我嘗試了這個:package mainimport (    "fmt"    "sync")var ch1=make(chan int)var ch2=make(chan int)func f1() {    select {    case <- ch1:fmt.Println("ch1")    default: fmt.Println("default")    }}func f2() {    select {    case <- ch2:fmt.Println("ch2")    default: fmt.Println("default")    }}func w1() {    ch1 <-1}func w2() {    ch2 <-1}func main() {    var wg sync.WaitGroup    wg.Add(4)    go f1()    go f2()    go w1()    go w2()    wg.Wait()}這次的錯誤更多:defaultch2fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0x40e028, 0x0)    /usr/local/go/src/runtime/sema.go:56 +0x40sync.(*WaitGroup).Wait(0x40e020, 0x14b720)    /usr/local/go/src/sync/waitgroup.go:130 +0x60main.main()    /tmp/sandbox916639182/prog.go:36 +0x100goroutine 8 [chan send]:main.w1()    /tmp/sandbox916639182/prog.go:23 +0x40created by main.main    /tmp/sandbox916639182/prog.go:34 +0xc0我哪里出錯了,如何解決?
查看完整描述

2 回答

?
哆啦的時光機

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

您的main()函數嘗試在所有通道上發送,并且只有一次嘗試在單獨的并發 goroutine 中從這些通道中讀取。這是否成功取決于 goroutine 調度程序。如果非阻塞接收f2()比發送更早安排main(),那么后面的發送main()將永遠阻塞(沒有人會再次嘗試接收ch2)。


擺脫死鎖的一種方法是使用接收操作而不是非阻塞接收(在Go Playground上嘗試):


func f1() {

    <-ch1

    fmt.Println("ch1")

}

func f2() {

    <-ch2

    fmt.Println("ch2")

}

因此,無論何時main()在這些通道上發送值,總會有一個接收器準備好繼續,所以main()不會卡住。


請注意,當main()返回時,應用程序結束,它不會等待非主 goroutine 完成。因此,您可能無法在控制臺上看到ch1和打印。ch2有關詳細信息,請參閱Go 中的 goroutine 沒有輸出。


如果您的意圖是在您的應用程序存在之前等待所有 goroutine 完成它們的工作,請使用sync.WaitGroup它(在Go Playground上嘗試):


var ch1 = make(chan int)

var ch2 = make(chan int)


var wg sync.WaitGroup


func f1() {

    defer wg.Done()

    <-ch1

    fmt.Println("ch1")

}


func f2() {

    defer wg.Done()

    <-ch2

    fmt.Println("ch2")

}


func main() {

    wg.Add(1)

    go f1()

    wg.Add(1)

    go f2()


    ch1 <- 1

    ch2 <- 2

    wg.Wait()

}

在此處查看更多示例:解決 goroutines 死鎖;并防止 main() 函數在 goroutine 在 Golang 中完成之前終止。


另一種選擇是為通道提供 1 的緩沖區,因此main()可以在沒有接收器準備好從通道接收的情況下在通道上發送 1 值(在Go Playground上試試這個):


var ch1 = make(chan int, 1)

var ch2 = make(chan int, 1)

有了這個,可以在沒有and的main()情況下繼續,所以再一次,不能保證你會看到任何打印出來的東西。f1()f2()


查看完整回答
反對 回復 2022-04-26
?
嚕嚕噠

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

此處使用的通道是無緩沖通道。

  • 當 main goroutines 啟動時,它會創建兩個新的 goroutine f1 和 f2。

  • 當執行 f1 或 f2 時,它將檢查我們是否在通道中有值,否則它將打印默認消息并退出。

  • 理想情況下,channels 會先發布值,然后通過 goroutine 接收

  • 實際情況是 goroutine 通過打印默認情況退出,但主 goroutine 試圖在通道中發布值,但由于沒有接收器,它面臨死鎖情況。

從第一個示例中刪除了死鎖,請參考鏈接: https: //play.golang.org/p/6RuQQwC9JkA

但是,如果 main 例程退出,所有關聯的 goroutine 將被自動終止。這就是為什么我們可以看到該值是任意打印的。

從第二個示例中刪除了死鎖,請參閱鏈接: https: //play.golang.org/p/yUmc_jjZMgV

sync.WaitGroup 正在讓 main goroutine 等待,這就是為什么我們可以在每次程序執行時觀察輸出。


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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