簡體   English   中英

Golang入站通道未在goroutine中接收

[英]Golang inbound channel not receiving inside a goroutine

請幫助我了解為什么在這種情況下為什么未<-done入站<-done頻道?

func main() {
    done := make(chan bool)
    println("enter")
    defer func() {
        println("exit")
    }()
    defer func() {
        println("  notify start")
        done <- true
        println("  notify end")
    }()     
    go func() {
        println("    wait start")
        <-done
        println("    wait end")
    }()
    time.Sleep(time.Millisecond) // << when this is removed, it works.
}

我期望輸出為:

enter
  notify start
    wait start
    wait end
  notify end
exit

而是:

enter
    wait start
  notify start
  notify end
exit

最初,我認為done通道會以某種方式提前關閉或清理,但是即使done是全局的,它也會導致相同的意外行為。

done <- true <-done之前,不應該<-done阻塞? 反之亦然?

解析度

似乎我期望程序在退出之前等待所有goroutine完成。 這是一個錯誤的假設。

這是一個骯臟的解決方法:

func main() {
    done, reallydone := make(chan bool), make(chan bool)
    println("enter")
    defer func() {
        <-reallydone
        println("exit")
    }()
    go func() {
        println("    wait start")
        <-done
        println("    wait end")
        reallydone <- true
    }()
    defer func() {
        println("  notify start")
        done <- true
        println("  notify end")
    }()
    time.Sleep(time.Millisecond)
}

當您使用sleep時,它將給goroutine啟動時間,然后在它從通道讀取時,主出口在調用最后一個println(" wait end")之前退出。

但是,如果您不調用sleep,則defer將阻塞,直到goroutine從goroutine中讀取並為其提供了足夠的打印時間。

如果將代碼移到其他函數並從main調用,它將按預期工作。

func stuff() {
    done := make(chan bool)
    println("enter")
    defer func() {
        println("exit")
    }()
    go func() {
        println("    wait start")
        <-done
        println("    wait end")
    }()
    defer func() {
        println("  notify start")
        done <- true
        println("  notify end")
    }()
}
func main() {
    stuff()
}

done通道上的事件序列:“ [通道未緩沖時,僅當發送方和接收方都准備就緒時,通信才成功”。 例如,

done通道是未緩沖的: main

done := make(chan bool)

接收等待發送: go func()

<-done 

接收就緒( <-done ),發送: defer func()

done <- true

main函數結束,並且不等待goroutine( go func() )完成。

輸出:

enter
    wait start
  notify start
  notify end
exit

Go編程語言規范

頻道類型

通道提供了一種機制,用於通過發送和接收指定元素類型的值來同時執行功能以進行通信。 未初始化通道的值為nil。

可以使用內置函數make創建新的初始化通道值,該函數將通道類型和可選容量作為參數:

 make(chan int, 100) 

容量(以元素數為單位)設置通道中緩沖區的大小。 如果容量為零或不存在,則通道是無緩沖的,並且僅在發送方和接收方都准備就緒時通信才能成功。 否則,如果緩沖區未滿(發送)或不為空(接收),則通道將被緩沖,並且通信將成功進行而不會阻塞。 零通道永遠不會准備好進行通信。

轉到語句

程序執行首先初始化主程序包,然后調用函數main。 當該函數調用返回時,程序退出。 它不等待其他(非主)goroutine完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM