第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

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

為什么在 defer 語句中關(guān)閉通道會出現(xiàn)恐慌?

為什么在 defer 語句中關(guān)閉通道會出現(xiàn)恐慌?

Go
HUH函數(shù) 2023-07-31 10:50:34
在下面的示例中,go 例程將值泵入無緩沖通道,并且 main 函數(shù)對其進行迭代。package mainimport (    "fmt"    "strconv")var chanStr chan stringfunc main() {    go pump()    fmt.Println("iterating ...")    for val := range chanStr {        fmt.Printf("fetched val: %s from channel\n", val)    }}func pump() {    defer 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)    }    //close(chanStr)}該函數(shù)會出現(xiàn)恐慌并輸出以下內(nèi)容:iterating ...                                             pumping seq 1 into channel                                pumping seq 2 into channel                                fetched val: val1 from channel                            ......fetched val: val4 from channel                            pumping seq 5 into channel                                panic: close of nil channel                               goroutine 5 [running]:                                    main.pump()                                                       C:/personal/gospace/go-rules/test.go:26 +0x1a6    created by main.main                                              C:/personal/gospace/go-rules/test.go:11 +0x4e     但是,如果我評論 defer 語句并在 goroutine 中的 for 循環(huán)之后立即關(guān)閉pump,接收器不會驚慌。 這兩種情況有什么區(qū)別?看起來 defer 在收到值之前關(guān)閉通道,但常規(guī)關(guān)閉會等待。此外,當我使用競爭檢測器進行構(gòu)建時,即使在常規(guī)關(guān)閉中,它也會標記潛在的競爭條件(我無法每次都重新創(chuàng)建競爭)。這是否意味著這兩種方式都不能優(yōu)雅地關(guān)閉通道?更新: 對于所有評論,我知道問題是什么。我必須在函數(shù)的第一行創(chuàng)建通道m(xù)ain()。不過,我在 Windows 上運行 go1.12,并且觀察到了這種行為。顯然我沒有偽造輸出。我一直使用 defer 語句重新創(chuàng)建恐慌,甚至在 for 循環(huán)后立即關(guān)閉通道時也沒有發(fā)生過恐慌pump()
查看完整描述

3 回答

?
梵蒂岡之花

TA貢獻1900條經(jīng)驗 獲得超5個贊

您的代碼在不同方面都非?;顫姡?/p>


for val在 goroutine 實際初始化通道之前,您有可能(事實上,很有可能)開始從循環(huán)中的通道讀取數(shù)據(jù),從而導(dǎo)致死鎖。


iterating ...

pumping seq 1 into channel

fatal error: all goroutines are asleep - deadlock!

事實上,這是我觀察到的在本地或操場上按原樣執(zhí)行代碼的唯一行為。


如果我添加一個延遲,


 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

原因是你在調(diào)用close(chanStr)時chanStr仍然為零。defer如果您在創(chuàng)建頻道后致電您:


func pump() {

    chanStr = make(chan string)

    defer close(chanStr)

你會解決這個問題的。


要解決這兩個競爭,您需要在調(diào)用 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)

    }

}

在這種情況下,延遲函數(shù)是 的閉包chanStr,因此chanStr的計算被延遲到實際執(zhí)行。在此版本中,當延遲函數(shù)執(zhí)行時,chanStr不再為 nil,因此無需恐慌。


查看完整回答
反對 回復(fù) 2023-07-31
?
手掌心

TA貢獻1942條經(jīng)驗 獲得超3個贊

主 go 例程有可能在創(chuàng)建通道之前從通道中讀取數(shù)據(jù)。這就是你的數(shù)據(jù)競賽。

應(yīng)在開始您的 go 例程之前創(chuàng)建通道。

修復(fù): https: //play.golang.org/p/O7pgM05KEtI


查看完整回答
反對 回復(fù) 2023-07-31
?
慕標5832272

TA貢獻1966條經(jīng)驗 獲得超4個贊

您發(fā)布的代碼存在死鎖情況。您可能沒有發(fā)布相同的代碼。


這是應(yīng)該可以工作的更新后的代碼:


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)

}


本例中的問題是,您在函數(shù)內(nèi)部創(chuàng)建了通道pump,因此主函數(shù)不知道如何使用數(shù)據(jù),并且由于沒有使用者而導(dǎo)致死鎖。


查看完整回答
反對 回復(fù) 2023-07-31
  • 3 回答
  • 0 關(guān)注
  • 257 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號