KEMBAR78
Go Concurrency Basics | PPTX
Go Concurrency Basics
Goroutines, channels and standard library
By Vitalii Perehonchuk, Software Developer
www.eliftech.com
Go provides
Concurrent execution
Synchronization and messaging
Multi-way concurrent control
www.eliftech.com
Go does NOT provide
direct thread manipulation
Go multithreading is fully managed by Go runtime.
In Go you use goroutines in place of threads
www.eliftech.com
Go provides a race detector
Ran with “-race” flag. It watches for unsynchronized access to shared variables.
www.eliftech.com
Goroutine
▪ A lightweight “thread” of execution managed by Go runtime.
▪ A function ran independently in the same address space as other goroutines.
▪ It’s routine to create thousands of goroutines.
▪ Go web servers usually process each request
in a separate goroutine.
www.eliftech.com
Goroutine
func sidekick() {
// Will be never executed.
fmt.Println("Sidekick arrived")
}
func main() {
go sidekick()
fmt.Println("Hero arrived")
}
www.eliftech.com
Goroutine
func sidekick() {
// Will be executed this time.
fmt.Println("Sidekick arrived")
}
func main() {
go sidekick()
runtime.Gosched()
fmt.Println("Hero arrived")
}
www.eliftech.com
Goroutine anti-pattern
Do not create functions whose only purpose is to run a goroutine.
www.eliftech.com
Channel
Imagine it as a pipe
<-
<-
for communication of goroutines
www.eliftech.com
Channel
Imagine it as a pipe
for communication of goroutines
www.eliftech.com
Channel
A goroutine can wait for a value from a channel
www.eliftech.com
Channel
A goroutine can wait for a value from a channel
func main() {
myChan := make(chan int)
<- myChan
// deadlock
fmt.Println("Hi everyone")
}
www.eliftech.com
Channel
A goroutine can wait to send a value to a channel
func main() {
myChan := make(chan int)
myChan <- 1
// deadlock
fmt.Println("Hi everyone")
}
www.eliftech.com
Channel
A goroutine can close a channel
func sidekick(mChan chan<- string)
{
mChan <- "I have not so
much to say"
mChan <- "Sorry"
close(mChan)
}
func main() {
wfm := true
var m string
mChan := make(chan string)
go sidekick(mChan)
for {
m, wfm = <-mChan
if !wfm { break }
fmt.Printf("Message from
the sidekick: %sn", m)
}
fmt.Println("Thanks for
your attention.")
}
www.eliftech.com
Channel
A deadlock can occur when sending into channel
func sidekick(taskChannel <-chan
string) {
task := <- taskChannel
fmt.Printf(“Done: %sn”,
task)
fmt.Println(“Enough work
for today”)
}
func main() {
taskChannel := make(chan string)
go sidekick(taskChannel)
taskChannel <- “Wash the
dishes”
// deadlock
taskChannel <- “Do
laundry”
}
www.eliftech.com
Channel
A channel can have a buffer
func sidekick(taskChannel <-chan
string) {
task := <- taskChannel
fmt.Printf(“Done: %sn”,
task)
fmt.Println(“Enough work
for today”)
}
func main() {
taskChannel := make(chan string, 1)
go sidekick(taskChannel)
taskChannel <- “Wash the
dishes”
taskChannel <- “Do
laundry”
}
www.eliftech.com
Channel
“select” waits for a value from a set of channels
func sidekick() {
task := <-taskChan
time.Sleep(2 * time.Second)
resChan <- fmt.Sprintf(
"Done: %sn", task,
)
}
func main() {
// channels initialization
omitted
go sidekick(taskChan, resChan)
taskChan <- "Wash the dishes"
timer := time.NewTimer(1 *
time.Second)
var res string
select {
...
www.eliftech.com
Channel
“select” waits for a value from a set of channels
func sidekick() {
task := <-taskChan
time.Sleep(2 * time.Second)
resChan <- fmt.Sprintf(
"Done: %sn", task,
)
}
...
select {
case res = <- resChan:
fmt.Println(res)
case <- timer.C:
fmt.Println("SIDEKICK!")
fmt.Println("What are you
doing?")
}
}
www.eliftech.com
Channel anti-pattern
Do not guard channels with mutexes.
Channels don’t need concurrency control.
They are concurrency control.
www.eliftech.com
Utilities
runtime, sync
www.eliftech.com
type sync.Mutex
▪ Mutual exclusion lock.
▪ Zero value is unlocked
www.eliftech.com
type sync.WaitGroup
Makes a goroutine block until some work is done
www.eliftech.com
type sync.Mutex, type sync.WaitGroup
var c = 0
var cMutex sync.Mutex
var waitGroup sync.WaitGroup
func sidekick() {
cMutex.Lock()
c ++
cMutex.Unlock()
waitGroup.Done()
}
func main() {
waitGroup.Add(n)
for i := 0; i < n; i++ {
go sidekick()
}
waitGroup.Wait()
cMutex.Lock()
fmt.Printf("Counter's value:
%dn", c)
cMutex.Unlock()
}
www.eliftech.com
type sync.RWMutex
Reader / writer mutual exclusion
lock. Many readers, single writer
simultaneously
type sync.Once
Performs only one action only once
www.eliftech.com
type sync.Pool type sync.Map type sync.Cond
Thread-safe collection
of temporary objects
Map safe for
concurrent use
Condition object used
to announce an event
www.eliftech.com
runtime.GOMAXPROCS(int) int
▪ Function to set maximum number of native threads run simultaneously.
▪ Defaults to number of CPUs (since Go 1.6, previously defaulted to 1)
www.eliftech.com
runtime.NumGoroutine() int
Returns the number of goroutines that currently exist.
www.eliftech.com
runtime.Gosched()
Explicitly make Go scheduler switch contexts - let other goroutines run
www.eliftech.com
Conclusion
Go concurrency is cheap
Go concurrency is complicated (as any concurrency)
Go concurrency is powerful
www.eliftech.com
Sources
▪ “Mastering concurrency in Go” by Nathan Kozyra
▪ Golang.org
▪ “Learning Go’s concurrency through illustrations” by Trevor Forrey
▪ “Go Antipatterns” at hackmongo.com
www.eliftech.com
Don't forget to subscribe not to
miss our next presentations!
Find us at eliftech.com
Have a question? Contact us:
info@eliftech.com

Go Concurrency Basics