KEMBAR78
The async/await concurrency pattern in Golang | PDF
The await/async
concurrency pattern
January, 29th - Torino, Toolbox Coworking
…in Golang
Matteo Madeddu
Github: @made2591
Role: Devops, AWS, miscellanea
matteo.madeddu@gmail.com
Work: enerbrain.com
Blog: madeddu.xyz
A bit of history
Version 1.0
released
March, 2012
Go first appeared
in Google,
2007
November, 2009
Google announce Golang
to the worldwide
community
June, 2017
I released a
go-perceptron
on Github
Golang Developer Group
begins in Turin
January, 2020
2020
The community
grows!
github.com/docker/engine
github.com/docker/engine
github.com/kubernetes/kubernetes
github.com/docker/engine
github.com/kubernetes/kubernetes
github.com/hashicorp/terraform
github.com/docker/engine
github.com/kubernetes/kubernetes
github.com/hashicorp/terraform
github.com/prometheus/prometheus
github.com/docker/engine
github.com/kubernetes/kubernetes
github.com/hashicorp/terraform
github.com/grafana/grafana
github.com/prometheus/prometheus
github.com/docker/engine
github.com/kubernetes/kubernetes
github.com/hashicorp/terraform
github.com/gohugoio/hugo
github.com/grafana/grafana
github.com/prometheus/prometheus
it’s statically typed
it’s statically typed
it’s compiled
it’s statically typed
it’s compiled
and provide
interesting concurrency primitives to final users
Hello World
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
package main
import "fmt"
func main() {
var a = "initial"
fmt.Println(a) # initial
var b, c int = 1, 2
fmt.Println(a, b) # 1, 2
var d = true
fmt.Println(d) # true
var e int
fmt.Println(e) # 0
f := "apple"
fmt.Println(f) # apple
}
Concurrency
Dealing with many things at once.
Concurrency
Dealing with many things at once.
Parallelism
Doing many things at once.
Concurrency is the composition of independently
executing processes, while parallelism is the
simultaneous execution of (possibly related)
computations.
Introducing
goroutines
package main
import (
"fmt"
"time"
)
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
f("direct")
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
time.Sleep(time.Second)
fmt.Println("done")
}
Introducing
goroutines
package main
import (
"fmt"
"time"
)
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
f("direct")
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
time.Sleep(time.Second)
fmt.Println("done")
}
# standard function call
Introducing
goroutines
package main
import (
"fmt"
"time"
)
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
f("direct")
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
time.Sleep(time.Second)
fmt.Println("done")
}
# standard function call
# to invoke this function
in a goroutine, use go f(s).
This new goroutine will
execute concurrently with
the calling one.
When we run this program, we see
the output of the blocking call
first, then the interleaved output of
the two goroutines.
This interleaving reflects the
goroutines being run concurrently
by the Go runtime.
Introducing
channels
Channels are the pipes that connect
concurrent goroutines.
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
Introducing
channels
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
# channels are typed by the
values they convey
Introducing
channels
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
# channels are typed by the
values they convey
# when we run the program
the "ping" message is
successfully passed from one
goroutine to another via our
channel.
Introducing
channels
By default sends and receives block until
both the sender and receiver are ready.
This property allowed us to wait at the end
of our program for the "ping" message
without having to use any other
synchronization.
Philosophically, the idea behind Go is:
Don't communicate by sharing
memory; share memory by
communicating.
The await/async
concurrency pattern
The await/async
is special syntax to work with
Promises in a more comfortable way
Promise
A promise is a special JavaScript
object that let links production and
consuming code
async
Before a function means “this function
always returns a Promise”
Promise
A promise is a special JavaScript
object that let links production and
consuming code
async
Before a function means “this function
always returns a Promise”
await
Works only inside async function and makes
JavaScript wait until that Promise settles
and returns its result
Promise
A promise is a special JavaScript
object that let links production and
consuming code
const sleep = require('util').promisify(setTimeout)
async function myAsyncFunction() {
await sleep(2000)
return 2
};
(async function() {
const result = await myAsyncFunction();
// outputs `2` after two seconds
console.log(result);
})();
// ... package main and imports
func myAsyncFunction() <-chan int32 {
r := make(chan int32)
go func() {
defer close(r)
// work to be completed
time.Sleep(time.Second * 2)
r <- 2
}()
return r
}
func main() {
r := <-myAsyncFunction()
// outputs `2` after two seconds
fmt.Println(r)
}
Promise.all()
const myAsyncFunction = (s) => {
return new Promise((resolve) => {
setTimeout(() => resolve(s), 2000);
})
};
(async function() {
const result = await Promise.all([
myAsyncFunction(2),
myAsyncFunction(3)
]);
// outputs `2, 3` after two seconds
console.log(result);
})();
// ... package main and imports
func myAsyncFunction() <-chan int32 {
r := make(chan int32)
go func() {
defer close(r)
// work to be completed
time.Sleep(time.Second * 2)
r <- 2
}()
return r
}
func main() {
firstChannel, secondChannel :=
myAsyncFunction(2), myAsyncFunction(3)
first, second := <-firstChannel, <-secondChannel
// outputs `2, 3` after two seconds
fmt.Println(first, second)
}
The cool thing about channels is that
you can use Go's select statement
to implement concurrency patterns
and wait on multiple channel
operations.
Promise.race()
const myAsyncFunction = (s) => {
return new Promise((resolve) => {
setTimeout(() => resolve(s), 2000);
})
};
(async function() {
const result = await Promise.race([
myAsyncFunction(2),
myAsyncFunction(3)
]);
// outputs `2` or `3` after two seconds
console.log(result);
})();
// ... package main and imports
func myAsyncFunction() <-chan int32 {
r := make(chan int32)
go func() {
defer close(r)
// work to be completed
time.Sleep(time.Second * 2)
r <- 2
}()
return r
}
func main() {
var r int32
select {
case r = <-myAsyncFunction(2)
case r = <-myAsyncFunction(3)
}
// outputs `2` or `3` after two seconds
fmt.Println(r)
}
https://tour.golang.org/
https://madeddu.xyz/posts/go-async-await/
https://blog.golang.org/concurrency-is-not-parallelism
https://gobyexample.com/non-blocking-channel-operations
Thank you!
Matteo Madeddu
Github: @made2591
Role: Devops, AWS, miscellanea
matteo.madeddu@gmail.com
Work: enerbrain.com
Blog: madeddu.xyz

The async/await concurrency pattern in Golang