3 回答

TA貢獻1900條經驗 獲得超5個贊
您的代碼在不同方面都非常活潑:
for val在 goroutine 實際初始化通道之前,您有可能(事實上,很有可能)開始從循環中的通道讀取數據,從而導致死鎖。
iterating ...
pumping seq 1 into channel
fatal error: all goroutines are asleep - deadlock!
事實上,這是我觀察到的在本地或操場上按原樣執行代碼的唯一行為。
如果我添加一個延遲,
fmt.Println("iterating ...")
time.Sleep(10 * time.Millisecond) // Delay ensures the channel has been created
for val := range chanStr {
然后我確實觀察了您注意到的行為:
iterating ...
pumping seq 1 into channel
fetched val: val1 from channel
pumping seq 2 into channel
pumping seq 3 into channel
fetched val: val2 from channel
fetched val: val3 from channel
pumping seq 4 into channel
pumping seq 5 into channel
fetched val: val4 from channel
fetched val: val5 from channel
panic: close of nil channel
原因是你在調用close(chanStr)時chanStr仍然為零。defer如果您在創建頻道后致電您:
func pump() {
chanStr = make(chan string)
defer close(chanStr)
你會解決這個問題的。
要解決這兩個競爭,您需要在調用 goroutine之前初始化通道。完整代碼:
package main
import (
"fmt"
"strconv"
)
var chanStr chan string
func main() {
chanStr = make(chan string)
go pump(chanStr)
fmt.Println("iterating ...")
for val := range chanStr {
fmt.Printf("fetched val: %s from channel\n", val)
}
}
func pump(chanStr chan string) {
defer close(chanStr)
for i := 1; i <= 5; i++ {
fmt.Printf("pumping seq %d into channel\n", i)
chanStr <- "val" + strconv.Itoa(i)
}
}
為了進一步說明問題是立即defer close(chanStr)評估chanStr(當它仍然是nil)時,請考慮這個(不推薦?。┨娲鉀Q方案:
package main
import (
"fmt"
"strconv"
"time"
)
var chanStr chan string
func main() {
go pump()
fmt.Println("iterating ...")
time.Sleep(10 * time.Millisecond)
for val := range chanStr {
fmt.Printf("fetched val: %s from channel\n", val)
}
}
func pump() {
defer func() {
close(chanStr)
}()
chanStr = make(chan string)
for i := 1; i <= 5; i++ {
fmt.Printf("pumping seq %d into channel\n", i)
chanStr <- "val" + strconv.Itoa(i)
}
}
在這種情況下,延遲函數是 的閉包chanStr,因此chanStr的計算被延遲到實際執行。在此版本中,當延遲函數執行時,chanStr不再為 nil,因此無需恐慌。

TA貢獻1942條經驗 獲得超3個贊

TA貢獻1966條經驗 獲得超4個贊
您發布的代碼存在死鎖情況。您可能沒有發布相同的代碼。
這是應該可以工作的更新后的代碼:
package main
import (
? ? "fmt"
? ? "strconv"
)
func main() {
? ? chanStr := make(chan string)
? ? go pump(chanStr)
? ? fmt.Println("iterating ...")
? ? for val := range chanStr {
? ? ? ? fmt.Printf("fetched val: %s from channel\n", val)
? ? }
}
func pump(ch chan string) {
? ? defer close(ch)
? ? for i := 1; i <= 5; i++ {
? ? ? ? fmt.Printf("pumping seq %d into channel\n", i)
? ? ? ? ch <- "val" + strconv.Itoa(i)
? ? }
? ? //close(chanStr)
}
本例中的問題是,您在函數內部創建了通道pump,因此主函數不知道如何使用數據,并且由于沒有使用者而導致死鎖。
- 3 回答
- 0 關注
- 243 瀏覽
添加回答
舉報