Reputation: 13
I'm learning the Go language. Can someone please explain the output here?
package main
import "fmt"
var c = make(chan int, 1)
func f() {
c <- 1
fmt.Println("In f()")
}
func main() {
go f()
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
Output:
In f()
2
1
Process finished with exit code 0
Why did "In f()" occur before "2"? If "In f()" is printed before "2", the buffered channel should block. But this didn't happen, why?
The other outputs are reasonable.
Upvotes: 0
Views: 119
Reputation: 17415
The order of events that cause this to run through are these:
2
to the channel. Capacity of the channel is now exhausted.1
to the channel.The order of events that cause this to deadlock are these:
1
to the channel. Capacity of the channel is now exhausted.2
to the channel. Since the channel's buffer is full, this blocks.The output you provide seems to indicate that the goroutine finishes first and the program doesn't deadlock, which contradicts above two scenarios as explanation. Here's what happens though:
2
to the channel.2
from the channel.1
to the channel.In f()
.2
received from the channel.1
from the channel.1
received from the channel.Keep in mind that you don't have any guarantees concerning the scheduling of goroutines unless you programmatically enforce them. When you start a goroutine, it is undefined when the first code of that goroutine are actually executed and how much the starting code progresses until then. Note that since your code relies on a certain order of events, it is broken by that definition, just to say that explicitly.
Also, at any point in your program, the scheduler can decide to switch between different goroutines. Even the single line fmt.Printtln(<-c)
consists of multiple steps and in between each step the switch can occur.
Upvotes: 2
Reputation: 4371
To reproduce block you have to run that code many times the easiest way to do it with test. You don't have block cause of luck. But it is not guaranteed:
var c = make(chan int, 1)
func f() {
c <- 1
fmt.Println("In f()")
}
func TestF(t *testing.T) {
go f()
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
and run with command:
go test -race -count=1000 -run=TestF -timeout=4s
where count
number of tests. It reproduces blocking to me.
Provide timeout to not wait default 10 minutes
Upvotes: 1