Visualizing Concurrency in Go
GopherCon, July 11, 2016
Ivan Danyliuk, Typeform
Number forms
Visualizations
How do you see
concurrency?
Hello, world!
package main
func main() {
ch := make(chan int)
go func() {
ch <- 42
}()
<-ch
}
Timer
func tick(d time.Duration) <-chan int {
c := make(chan int)
go func() {
time.Sleep(d)
c <- 1
}()
return c
}
func main() {
for i := 0; i < 24; i++ {
c := tick(100 * time.Millisecond)
<-c
}
}
Ping-pong
func main() {
var Ball int
table := make(chan int)
go player(table)
go player(table)
table <- Ball
time.Sleep(1 * time.Second)
<-table
}
func player(table chan int) {
for {
ball := <-table
ball++
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
Ping-pong
Ping-pong #3
func main() {
var Ball int
table := make(chan int)
go player(table)
go player(table)
go player(table)
table <- Ball
time.Sleep(1 * time.Second)
<-table
}
func player(table chan int) {
for {
ball := <-table
ball++
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
Ping-pong #36
func main() {
var Ball int
table := make(chan int)
for i := 0; i < 36; i++ {
go player(table)
}
table <- Ball
time.Sleep(1 * time.Second)
<-table
}
func player(table chan int) {
for {
ball := <-table
ball++
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
Fan-in
func producer(ch chan int, d time.Duration) {
for {
ch <- i
time.Sleep(d)
}
}
func reader(out chan int) {
for { <-out }
}
func main() {
ch, out := make(chan int), make(chan int)
go producer(ch, 100*time.Millisecond)
go producer(ch, 300*time.Millisecond)
go reader(out)
for { out <- <-ch }
}
Servers
func handler(c net.Conn) {
c.Write([]byte("ok"))
c.Close()
}
func main() {
l, err := net.Listen("tcp", ":5000")
if err != nil {
panic(err)
}
for {
c, err := l.Accept()
if err != nil {
continue
}
go handler(c)
}
}
Servers
func handler(c net.Conn, ch chan string) {
ch <- 11 // something
c.Write([]byte("ok"))
c.Close()
}
func main() {
l, err := net.Listen("tcp", ":5000")
if err != nil {
panic(err)
}
ch := make(chan string)
go logger(ch)
go server(l, ch)
select{}
}
func logger(ch chan int) {
for {
fmt.Println(<-ch)
}
}
func server(l net.Listener,
ch chan int) {
for {
c, err := l.Accept()
if err != nil {
continue
}
go handler(c, ch)
}
}
Workers / Fan-out
func main() {
var wg sync.WaitGroup
wg.Add(36)
go pool(&wg, 36)
wg.Wait()
}
func pool(wg *sync.WaitGroup, n int) {
tasks := make(chan int)
for i := 0; i < n; i++ {
go worker(tasks, wg)
}
for i := 0; i < 50; i++ {
tasks <- i
}
close(tasks)
}
func worker(tasks <-chan int,
wg *sync.WaitGroup) {
defer wg.Done()
for {
task, ok := <-tasks
if !ok {
return
}
d := time.Duration(task)
* time.Millisecond
time.Sleep(d)
fmt.Println("processing task", task)
}
}
Concurrent prime sieve
package main
import "fmt"
func main() {
ch := make(chan int)
go Generate(ch)
for i := 0; i < 10; i++ {
prime := <-ch
fmt.Println(prime)
out := make(chan int)
go Filter(ch, out, prime)
ch = out
}
}
func Generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i
}
}
func Filter(in, out <-chan int, prime int) {
for {
i := <-in
if i%prime != 0 {
out <- i
}
}
}
GOMAXPROCS
Go Concurrency Tracer
- Uses go execution tracer (go tool trace)
- Rewrites your code and runs it
- Collect the trace
- Analyze and correlate events
- Start web-server serving WebGL visualization
Rob Pike - Concurrency is not parallelism
Concurrency vs Parallelism
- What is parallelism?
- What is concurrency?
- Let's visualize it.