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