Go has built-in concurrency. Concurrency and parallel execution are different things: you need concurrency (program structure) to enable parallel execution; actual parallelism during execution depends on the hardware.
For concurrency, Go offers so-called Goroutines and Channels.
A Goroutine is a concurrent thread managed by the Go runtime.
To call a goroutine use the following:
Copy
package main
import("fmt""time")funcdoSomething(size int){for i :=0; i < size; i++{
fmt.Println(i)
time.Sleep(time.Second)}}funcmain(){godoSomething(10)// go statement before a function creates a goroutinegodoSomething(10)
time.Sleep(10*time.Second)}
If you run this program, you will see that both doSomething(10) functions work concurrently. You can wait with time.Sleep(10*time.Second) to see this in action.
Go offers channels for communication between goroutines. Channels may be buffered or unbuffered. You can create an unbuffered channel with the following:
Copy
ch:=make(chantype)
You can use this channel to send and receive messages with the <- operator.
Send to channel ch as follows:
Copy
ch <- v
Read from channel ch as follows:
Copy
v :=<-ch
Now write an example using channels:
Copy
package main
import("fmt""time")funcdoSomething(size int, c chanint){for i :=0; i < size; i++{
time.Sleep(100* time.Millisecond)}
c <- size
}funcmain(){
c :=make(chanint)godoSomething(10, c)godoSomething(20, c)godoSomething(30, c)
x, y, z :=<-c,<-c,<-c
fmt.Println(x, y, z)}
In this case, you do not need to use time.Sleep anymore, because sends and receives are blocked until the other side is ready.
To avoid blocking, you can create buffered channels:
Copy
c:=make(chanint,100)
When a buffered channel is full, sends to it are blocked. When one is empty, receives from it are blocked.
You can iterate over the values of a channel if it is closed:
Copy
package main
import("fmt""time")funcdoSomething(size int, c chanint){for i :=0; i < size; i++{
time.Sleep(100* time.Millisecond)}
c <- size
}funcdoAll(c chanint){
d:=make(chanint)godoSomething(10, d)godoSomething(20, d)godoSomething(30, d)
c <-(<-d)
c <-(<-d)
c <-(<-d)close(c)}funcmain(){
c :=make(chanint)godoAll(c)for i :=range c {
fmt.Println(i)}}
Always close the channel (c) before you iterate over it. If you want to wait for multiple communication operations, Go offers select. This works similar to switch:
Copy
package main
import("fmt""time")funcdoSomething(size int, c chanint){for i :=0; i < size; i++{
time.Sleep(100* time.Millisecond)}
c <- size
}funcmain(){
c, q :=make(chanint),make(chanint)
jobs :=5gofunc(){for i :=1; i <= jobs; i++{doSomething(i*10, c)}
q <-0// done}()for{select{case x :=<-c:// if we have a result
fmt.Println(x)case<-q:// if we are done
fmt.Println("Finished")returndefault:// if we are waiting
fmt.Print("...")
time.Sleep(time.Second)}}}