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

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

將通道從無緩沖更改為緩沖會阻止 goroutine 運行

將通道從無緩沖更改為緩沖會阻止 goroutine 運行

Go
動漫人物 2022-11-08 15:21:45
這是一個在 goroutine 中使用通道和選擇的練習。如果斷開連接通道更改為緩沖通道,則 goroutine 根本不會運行。為什么從無緩沖通道更改為緩沖通道會阻止運行 goroutine?func SelectDemo(wg *sync.WaitGroup) {    messageCh := make(chan int, 10)    disconnectCh := make(chan struct{})    //  go routine won't run if channel is buffered    //disconnectCh := make(chan struct{}, 1)    defer close(messageCh)    defer close(disconnectCh)    go func() {        fmt.Println("  goroutine")        wg.Add(1)        for {            select {            case v := <-messageCh:                fmt.Println(v)            case <-disconnectCh:                fmt.Println("  disconnectCh")                //  empty the buffered channel before exiting                for {                    select {                    case v := <-messageCh:                        fmt.Println(v)                    default:                        fmt.Println("  disconnection, return")                        wg.Done()                        return                    }                }            }        }    }()    fmt.Println("Sending ints")    for i := 0; i < 10; i++ {        messageCh <- i    }    fmt.Println("Sending done")    disconnectCh <- struct{}{}}這是從 main 調用函數的代碼。我使用等待組來確保 goroutine 在程序退出之前完成:wg := sync.WaitGroup{}ch09.SelectDemo(&wg)wg.Wait()
查看完整描述

2 回答

?
一只萌萌小番薯

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

該代碼邏輯有許多缺陷 - 其中一些是:

1- 由于messageCh被緩沖,此代碼沒有阻塞:


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

        messageCh <- i

    }

所以下一個代碼在快速運行路徑中:


disconnectCh <- struct{}{}

如果您進行disconnectCh緩沖,則此行也不會阻塞運行,并且該SelectDemo函數可能會在運行wg.Add(1).


所以:你必須把:


wg.Add(1)


go func() {

2-即使使用wg.Add(1)之前的go func() { 代碼-

您也有:


    defer close(messageCh)

    defer close(disconnectCh)

這將在函數返回時關閉兩個通道SelectDemo這select是一個隨機選擇,因為兩個通道都準備好了:


fmt.Println("  goroutine")

        for {

            select {

            case v := <-messageCh:

                fmt.Println(v)

            case <-disconnectCh:

第二個選擇很可能是:


                for {

                    select {

                    case v := <-messageCh:

                        fmt.Println(v)

                    default:

                        fmt.Println("  disconnection, return")

                        wg.Done()

                        return

                    }

                }

將在messageCh關閉后0永遠運行,在讀取通道數據后永遠返回:


case v := <-messageCh:

    fmt.Println(v)


查看完整回答
反對 回復 2022-11-08
?
犯罪嫌疑人X

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

程序執行速度快


訪問網址:https ://pkg.go.dev/sync#WaitGroup.Add


請注意,當計數器為零時發生的具有正增量的調用必須在等待之前發生。具有負增量的調用或具有正增量的調用在計數器大于零時開始,可能隨時發生。通常這意味著對 Add 的調用應該在創建 goroutine 的語句或其他要等待的事件之前執行。如果重用 WaitGroup 來等待多個獨立的事件集,則必須在所有先前的 Wait 調用都返回后發生新的 Add 調用。請參閱 WaitGroup 示例。


func SelectDemo(wg *sync.WaitGroup) {


    messageCh := make(chan int, 10)

    disconnectCh := make(chan struct{}, 1)

    //  go routine won't run if channel is buffered

    //disconnectCh := make(chan struct{}, 1)


    wg.Add(1)


    defer close(messageCh)

    defer close(disconnectCh)

    go func() {

        fmt.Println("  goroutine")

        for {

            select {

            case v := <-messageCh:

                fmt.Println(v)

            case <-disconnectCh:

                fmt.Println("  disconnectCh")

                //  empty the buffered channel before exiting


                fmt.Println("  disconnection, return")

                wg.Done()

                return

            }

        }

    }()


    fmt.Println("Sending ints")

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

        messageCh <- i

    }


    //Delay sending exit signal

    time.Sleep(3 * time.Second)


    fmt.Println("Sending done")

    disconnectCh <- struct{}{}

}


我修改了你的代碼


再試一次?。?!


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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