我是 Golang 的新手,我很難弄清楚為什么下面的代碼會產生死鎖。另外,我該如何修復它才能正常作業?
package main
import "fmt"
func main() {
m := make(map[int]chan string)
go func() {
m[0] = make(chan string)
m[0] <- "abab"
}()
fmt.Println(<-m[0])
}
編輯:
感謝您的回答!不幸的是,初始化m[0]為
m[0] = make(chan string)
在啟動一個新的 goroutine 之前并不是我想要的。我的問題是:有沒有辦法“動態”創建頻道?例如,我有一個m型別的映射,map[int]chan string我收到包含類似id型別的請求int。我想通過 channel 發送一條訊息map[id],但是為每個初始化 channel 的int成本太高了。我如何解決/解決這個問題?
所以,換句話說,我想為每個佇列都有一個單獨的作業佇列,id并懶惰地初始化每個佇列。
uj5u.com熱心網友回復:
OP 更新問題后更新答案
您可以只回圈映射中的所有鍵,也許還有另一個 goroutine 不斷回圈所有鍵。顯然,如果一個鍵沒有被初始化,那么它就不會出現在 for range 回圈中。對于每個鍵,你可以啟動一個 goroutine 來監聽,這樣它就不會阻塞,或者你可以使用緩沖通道,這樣它們就不會阻塞到緩沖區限制。您也可以最好使用 waitGroup,而不是 time.Sleep(),這些僅用于這個簡單的示例。
package main
import (
"fmt"
"time"
)
func main() {
m := make(map[int]chan string)
go func() {
m[0] = make(chan string)
m[0] <- "abab"
}()
time.Sleep(time.Second * 1) //sleep so the above goroutine initializes the key 0 channel
for key := range m{ //loop on all non-nil keys
fmt.Println(key)
go func(k int){ // goroutine to listen on this channel
fmt.Println(<- m[k])
}(key)
}
time.Sleep(time.Second * 1) //sleep so u can see the effects of the channel recievers
}
舊答案
流量是這樣的。主協程啟動。地圖已創建。主協程遇到另一個協程。它產生了 goroutine 并繼續它的生命。然后遇到這一行,,,這fmt.Println(<-m[0])是一個問題,因為map確實初始化了,但是map中的channel本身沒有初始化!當主協程到達時fmt.Println(<-m[0]),另一個協程還沒有初始化通道!所以這是一個簡單的修復,只需在產生 goroutine 之前初始化通道,你就可以開始了!
package main
import "fmt"
func main() {
m := make(map[int]chan string)
m[0] = make(chan string)
go func() {
m[0] <- "abab"
}()
fmt.Println(<-m[0])
}
編輯:請注意,這fmt.Println(<-m[0])是阻塞,這意味著如果在其他 goroutine 中,您沒有在通道上發送,您也會陷入死鎖,因為您試圖在沒有人實際發送的情況下在通道上接收。
uj5u.com熱心網友回復:
您需要同步頻道的創建。
就目前而言,您的主執行緒到達<-m[0]時m[0]仍然是一個未初始化的通道,并且在未初始化的通道上接收將永遠阻塞。
您的 go 例程創建了一個新通道并將其放置在 中m[0],但是主要的 go 例程已經在偵聽先前的零值。在這個新通道上發送也會永遠阻塞,因為沒有從中讀取任何內容,所以所有 go 例程都會阻塞。
要解決此問題,請移至m[0] = make(chan string)go 例程之上,使其同步發生。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/338488.html
