> Learn Golang Basics here

Goroutines & Concurrent

Goroutines

View day2.go file

package main

import (
"fmt"
"time"
)

func main() {
chanChanChanChan()
bufferedChan()
synchronizeTask()
pingPongGame()
selectChannel()
outOfTime()
nonBlockingChannelWithSelect()
closeChannel()
rangeOverChannel()
doSomethingLater()
doInterval()
}

func chanChanChanChan() {
chan1 := make(chan string)
chan2 := make(chan string)

// By default sends and receives block until both the sender and receiver are ready.
go func() {
fmt.Println("[1] Passing chan2 !")
chan2 <- "Chan2"
fmt.Println("[1] Passed chan2 !")
}()

go func() {
fmt.Println("[1] Receiving chan2 !")
chan2Msg := <-chan2
fmt.Println("[1] Received chan2 !")

chan2Msg += " Chan1"

fmt.Println("[1] Passing chan1 !")
chan1 <- chan2Msg
fmt.Println("[1] Passed chan1 !")
}()

fmt.Println("[1] Waiting for chan1 message ...")
msg := <-chan1
fmt.Println("[1] Message from goroutines :", msg)
}

func bufferedChan() {
chan1 := make(chan string, 2) // second parameter is number of messages the channel will handle, it creates Buffered Channel

go func() {
fmt.Println("[2] Passing chan2 !")
chan1 <- "Chan2" // Buffered Chan doesn't need to wait concurrent receiving
fmt.Println("[2] Passed chan2 !")
}()

go func() {
fmt.Println("[2] Passing chan1 !")
chan1 <- "Chan1" // Buffered Chan doesn't need to wait concurrent receiving
fmt.Println("[2] Passed chan1 !")
}()

fmt.Println("[2] Waiting for chan1 message ...")
time.Sleep(time.Second * 3) // Wait 3 seconds to wait message passing to buff chan
msg := <-chan1
msg += <-chan1
fmt.Println("[2] Message from buffered chan :")
}

func synchronizeTask() {
done := make(chan bool)

go func(ok chan bool) {
fmt.Println("[3] Working ...")
time.Sleep(time.Second)
fmt.Println("[3] Done ...")

ok <- true
}(done)

<-done
fmt.Println("[3] Lets relax !")
}

// Channel direction
func ping(rchan chan<- string, msg string) {
rchan <- msg
}

func pong(rchan <-chan string, schan chan<- string) {
tmp := <-rchan
schan <- tmp
}

func pingPongGame() {
chan1 := make(chan string, 1)
chan2 := make(chan string, 1)

ping(chan1, "Game over !")
pong(chan1, chan2)
pingPongMsg := <-chan2
fmt.Println("[4] Ping pong message :", pingPongMsg)
}

func selectChannel() {
c1 := make(chan string)
c2 := make(chan string)

go func() {
time.Sleep(time.Second)
c1 <- "msg1"
}()

go func() {
time.Sleep(time.Second * 2)
c2 <- "msg2"
}()

// Wait multi channel, whole func take ~2 seconds because of sleeping concurrently
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("[5] Received :", msg1)
case msg2 := <-c2:
fmt.Println("[5] Received :", msg2)
}
}
}

func outOfTime() { // Timeout using select channel
chan1 := make(chan string)

go func() {
time.Sleep(time.Second * 2)
chan1 <- "here result after 2 seconds"
}()

select {
case msg := <-chan1:
fmt.Println("[6] Message from chan1", msg)
case <-time.After(time.Second):
fmt.Println("[6] Your time is out ! You only have 1 second !")
}
}

func nonBlockingChannelWithSelect() {
chan1 := make(chan string)

select {
case msg := <-chan1:
fmt.Println("[7] Ahh... got it !", msg)
default:
fmt.Println("[7] Nothing here !")
}
}

func closeChannel() {
jobs := make(chan string, 3)
done := make(chan bool)

go func() {
for {
j, more := <-jobs
if more {
fmt.Println("[8] received a job", j)
} else {
fmt.Println("[8] received all jobs")
done <- true
}
}
}()

for i := 0; i < 3; i++ {
jobs <- "hahaha"
fmt.Println("[8] sent a job")
}
close(jobs)
fmt.Println("[8] sent all jobs")

<-done
}

func rangeOverChannel() {
chan1 := make(chan string, 3)
chan1 <- "1"
chan1 <- "2"
chan1 <- "3"

close(chan1)
for msg := range chan1 {
fmt.Println("[9] range over :", msg)
}
}

func doSomethingLater() {
timer1 := time.NewTimer(time.Second * 2)

<-timer1.C
fmt.Println("[10] timer1 is expired")

timer2 := time.NewTicker(time.Second * 2)
go func() {
<-timer2.C
fmt.Println("[10] timer2 is expired")
}()
timer2.Stop()
fmt.Println("[10] timer2 is stopped")
}

func doInterval() {
ticker := time.NewTicker(time.Millisecond * 500)
go func() {
for t := range ticker.C {
fmt.Println("[11] do job interval at", t)
}
}()
time.Sleep(time.Second * 3)
ticker.Stop()
fmt.Println("[11] Ticker is stopped")
}

Ref:

  • Lesson structure by gobyexample(dot)com
  • Photo by tensor-programming(dot)com