10/01/2020 - GO
This example uses Golang's unbuffered channels. Unbuffered channels contain one value at a time. Hence reason they are called a blocking channels and created like this: make(chan TYPE)
. To demonstrate the usage, we are going to greet cities one by one every 2 seconds. However, if there is 5 seconds delay in greeting, we will timeout the application. Please read the inline comments for detailed explanation.
If you increase sleeping time from 2 to 5/+ seconds below, the application would timeout without printing anything at all. There isn't a default
block in select
statement so it will block until either a message is received through our channel then carry on blocking or encounter a timeout case automatically then exit. The main
function is the receiver and the welcome
function is the sender in this case.
package main
import (
"fmt"
"os"
"time"
)
func main() {
// List of cities.
cities := []string{"London", "Istanbul", "Berlin", "Madrid"}
// Create unbuffered channel.
ch := make(chan string)
// Pass channel and cities to welcome function and run it as goroutine.
go welcome(ch, cities)
// Indefinitely wait for the channel to return something.
for {
select {
// If something was received through the channel, print it.
case msg := <-ch:
fmt.Println(msg)
// If nothing was received through the channel for 5 seconds, timeout.
case <-time.After(5 * time.Second):
fmt.Println("timeout")
os.Exit(0)
}
}
}
// welcome accepts write-only channel and list of cities.
func welcome(ch chan<- string, cities []string) {
// Loop through the cities.
for _, city := range cities {
// Sleep 2 seconds before writing to the channel below.
time.Sleep(1 * time.Second)
// Write (send) greeting message to the channel.
ch <- fmt.Sprintf("Welcome to %s", city)
}
}
$ go run -race cmd/client/main.go
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
timeout
This is simpler version because we don't use timeout. Instead, we close the channel explicitly.
package main
import (
"fmt"
"time"
)
func main() {
// List of cities.
cities := []string{"London", "Istanbul", "Berlin", "Madrid"}
// Create unbuffered channel.
ch := make(chan string)
// Pass channel and cities to welcome function and run it as goroutine.
go welcome(ch, cities)
// Indefinitely wait for the channel to return something.
for msg := range ch {
fmt.Println(msg)
}
fmt.Println("done")
}
// welcome accepts write-only channel and list of cities.
func welcome(ch chan<- string, cities []string) {
// Loop through the cities.
for _, city := range cities {
// Sleep 2 seconds before writing to the channel below.
time.Sleep(1 * time.Second)
// Write (send) greeting message to the channel.
ch <- fmt.Sprintf("Welcome to %s", city)
}
// Close the channel so that range loop knows when to exit.
close(ch)
}
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
done
In this case, we are passing cities one by one instead of all.
package main
import (
"fmt"
"time"
)
func main() {
// List of cities.
cities := []string{"London", "Istanbul", "Berlin", "Madrid"}
// Create unbuffered channel.
ch := make(chan string)
for _, city := range cities {
// Pass channel and city to welcome function and run it as goroutine.
go welcome(ch, city)
// Indefinitely wait for the channel to return something.
for msg := range ch {
fmt.Println(msg)
break
}
}
fmt.Println("done")
}
// welcome accepts write-only channel and city.
func welcome(ch chan<- string, city string) {
// Sleep 2 seconds before writing to the channel below.
time.Sleep(1 * time.Second)
// Write (send) greeting message to the channel.
ch <- fmt.Sprintf("Welcome to %s", city)
}
Welcome to London
Welcome to Istanbul
Welcome to Berlin
Welcome to Madrid
done