The document discusses Go's concurrency features including goroutines, channels, and synchronization tools. It explains that goroutines are lightweight threads managed by Go, and channels provide a means of communication between goroutines. The document also covers potential concurrency issues like deadlocks and provides best practices to avoid anti-patterns when using goroutines and channels.
3. 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
4. www.eliftech.com
Go provides a race detector
Ran with “-race” flag. It watches for unsynchronized access to shared variables.
5. 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.
12. 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")
}
13. 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")
}
14. 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.")
}
15. 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”
}
16. 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”
}
17. 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 {
...
18. 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?")
}
}
23. 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()
}
25. 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
31. 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