简体   繁体   中英

Golang inbound channel not receiving inside a goroutine

Please help me understand why the inbound <-done channel is not being picked up in this case?

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.
}

I'm expecting the output to be:

enter
  notify start
    wait start
    wait end
  notify end
exit

But instead it's:

enter
    wait start
  notify start
  notify end
exit

I initially assumed that the done channel was somehow being closed or cleaned up early, but it results in the same unexpected behavior even when the done is global.

Shouldn't <-done block until done <- true occurs? And vice versa?

Resolution

It seems that I was expecting the program to wait for all of the goroutines to completed before exiting. This is an incorrect assumption.

Here's an dirty workaround:

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)
}

When you use sleep, it gives time for the goroutine to start, then by the time it reads from the channel, main exits before the last println(" wait end") gets called.

However if you don't call sleep, defer will block until the goroutine reads from it and that gives it enough time to print.

If you move the code to a different function and call it from main it will work as expected.

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()
}

The sequence of events on the done channel: "[when] the channel is unbuffered communication succeeds only when both a sender and receiver are ready." For your example,

The done channel is unbuffered: main .

done := make(chan bool)

Receive waiting for a send: go func() .

<-done 

Receive ready ( <-done ), send: defer func() .

done <- true

The main function ends and does not wait for the goroutine ( go func() ) to finish.

Output:

enter
    wait start
  notify start
  notify end
exit

The Go Programming Language Specification

Channel types

A channel provides a mechanism for concurrently executing functions to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil.

A new, initialized channel value can be made using the built-in function make, which takes the channel type and an optional capacity as arguments:

 make(chan int, 100) 

The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives). A nil channel is never ready for communication.

Go statements

Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM