I just started learning Go recently and I was confused when I learning Goroutine. Here's my code. This intends to finish 3 processes concurrently.
package main
import (
"fmt"
"log"
"time"
)
func wait1(c chan string) {
time.Sleep(1 * time.Second)
log.Print("waited 1 sec")
c <- "wait1 finished
"
}
func wait2(c chan string) {
time.Sleep(2 * time.Second)
log.Print("waited 2 sec")
c <- "wait2 finished
"
}
func wait3(c chan string) {
time.Sleep(3 * time.Second)
log.Print("waited 3 sec")
c <- "wait3 finished
"
}
func main() {
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
}
For me, this part looks inputting different functions into the same channel called c and trying to print the values received from c.
c := make(chan string, 3)
log.Print("started")
go wait1(c)
go wait2(c)
go wait3(c)
w1, w2, w3 := <-c, <-c, <-c
log.Print("finished")
fmt.Println(w1, w2, w3)
However, as you can see, output is what I expected. It processes 3 functions at the same time and returns "finished" statement.
2015/11/25 09:41:31 started
2015/11/25 09:41:32 waited 1 sec
2015/11/25 09:41:33 waited 2 sec
2015/11/25 09:41:34 waited 3 sec
2015/11/25 09:41:34 finished
wait1 finished
wait2 finished
wait3 finished
Why it's unnecessary to create 3 different channels like c1, c2, c3...? Why value is not overwritten even though I'm using the same channel called c?
As far as I understood, you view channels as a variable. A variable that can hold some value. So if there was some value1
and you wrote another value2
you basically expect the value1
to disappear. Which is wrong.
Try to take a look at the channels as a buffer or a priority queue (some people find it crude comparison). Channel has it's size (your third variable 3
) which tells how many values can be simultaneously in it. Once you put something in the channel, you can view it as being processes with the priority equal to amount of time needed to finish this go-routine.
So in your case you put 3 elements in your priority queue with go wait()
and then extracted from a queue with w1, w2, w3 := <-c, <-c, <-c
. So nothing gets overwritten.
Unbuffered channels sync before sending data through. So in this case, your successive calls to <-c
in your assignment line block until the wait functions on the other end sends something through.
Markus makes an excellent point though and it should be pointed out that this w1, w2, w3 := <-c, <-c, <-c
only works because you've staggered the wait times for your different wait functions. If those functions waited an arbitrary amount of time before sending data on the channel, you would not have any guarantee that w2 gets assigned to the result sent from wait2. It would just be set to which ever value was the second value sent through the channel.