Reputation: 71
I'm a beginner of golang and I'm learning the goroutine and channel. Intuitively, I consider a gorountine in golang is essentially a thread running independently. Therefore, if there are more than one goroutine, the execution order won't be guaranteed. Hence, the following code should output "ping" and "pong" in a random order. However, what I observed is that the program yields "ping" and "pong" in turn. Can anyone explain the reason for me? Any reply would be helpful. Thanks!
Another intriguing observation I found is that if I don't call sleep function inside the printer function, the program will output in a random order.
package main
import (
"fmt"
"time"
)
func pinger(c chan string) {
for i := 0; ; i++ {
c <- "ping"
}
}
func printer(c chan string) {
for {
msg := <- c
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
func ponger(c chan string) {
for i := 0; ; i++ {
c <- "pong"
}
}
func main() {
var c chan string = make(chan string)
go pinger(c)
go ponger(c)
go printer(c)
var input string
fmt.Scanln(&input)
}
Upvotes: 5
Views: 1204
Reputation: 132018
To better understand consider the following statement and demo program:
To really see this you should run this on your machine:
package main
import (
"fmt"
"time"
)
func main() {
count := 10
c := make(chan int)
for i := 0; i < count; i++ {
go func(i int) {
c <- i + 1
}(i)
}
for i := 0; i < count; i++ {
fmt.Println("c", <-c)
}
fmt.Println()
d := make(chan int)
for i := 0; i < count; i++ {
go func(i int) {
d <- i + 1
}(i)
time.Sleep(time.Millisecond * 5)
}
for i := 0; i < count; i++ {
fmt.Println("d", <-d)
}
var input string
fmt.Scanln(&input)
}
Here is a playground, though it won't be as obvious what is happening because the first group (c
) will always appear in a consistent (though non-sorted) order. The second group (d
) will always appear in order on the playground or locally.
https://play.golang.org/p/JCVyVlFPRXS
These are the outputs from 3 runs locally
1 2 3
----------------
c 2 c 10 c 10
c 1 c 4 c 2
c 6 c 1 c 1
c 3 c 2 c 4
c 4 c 3 c 3
c 5 c 7 c 5
c 8 c 5 c 8
c 7 c 6 c 7
c 9 c 8 c 9
c 10 c 9 c 6
d 1 d 1 d 1
d 2 d 2 d 2
d 3 d 3 d 3
d 4 d 4 d 4
d 5 d 5 d 5
d 6 d 6 d 6
d 7 d 7 d 7
d 8 d 8 d 8
d 9 d 9 d 9
d 10 d 10 d 10
Upvotes: 3
Reputation: 166588
The Go Programming Language Specification
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.
You have an unbuffered channel: make(chan string)
.
msg := <- c
(ready to receive) and c <- "ping"
(ready to send): send and receive "ping"
.
msg := <- c
(ready to receive) and c <- "pong"
(ready to send): send and receive "pong"
.
Upvotes: 4