SlideShare a Scribd company logo
Go Containers
January 23, 2014 

John Graham-Cumming

www.cloudflare.com!
Six interesting containers
•  From pkg/container!
•  container/list!
•  container/ring!
•  container/heap

!
•  Built in
•  map!
•  slice
•  Channels as queues

www.cloudflare.com!
container/list!
•  Doubly-linked list implementation
•  Uses interface{} for values
l := list.New()!
e0 := l.PushBack(42)!
e1 := l.PushFront(13)!
Pity	
  there’s	
  no	
  ‘map’	
  
e2 := l.PushBack(7)!
func4on	
  
l.InsertBefore(3, e0)!
l.InsertAfter(196, e1)!
l.InsertAfter(1729, e2)!
!
for e := l.Front(); e != nil; e = e.Next() {!
fmt.Printf("%d ", e.Value.(int))!
}!
e.Value	
  to	
  get	
  the	
  
fmt.Printf("n")!
stored	
  value	
  
!
!
13 196 3 42 7 1729!
www.cloudflare.com!
container/list!

All	
  work	
  on	
  
elements	
  not	
  values	
  	
  

l.MoveToFront(e2)!
l.MoveToBack(e1)!
Returns	
  the	
  value	
  
l.Remove(e0)!
removed	
  
!
for e := l.Front(); e != nil; e = e.Next() {!
fmt.Printf("%d ", e.Value.(int))!
}!
fmt.Printf("n")!
!
!
7 196 3 1729 13!

www.cloudflare.com!
container/ring!
•  A circular ‘list’
parus := []string{”major", “holsti”, “carpi”}!
!
r := ring.New(len(parus))!
for i := 0; i < r.Len(); i++ {!
r.Value = parus[i]!
r = r.Next()!
}!
!
r.Do(func(x interface{}) {!
fmt.Printf(“Parus %sn”, x.(string))!
})!

•  Move n elements through ring
r.Move(n)!

www.cloudflare.com!
container/heap!
•  Implements a “min-heap” (i.e. tree where each node is

the “minimum” element in its subtree)

•  Needs a notion of “Less” and a way to “Swap”
www.cloudflare.com!
container/heap!
•  The single most confusing definition in all of Go
type Interface interface {!
sort.Interface!
Push(x interface{}) // add x as element Len()!
Pop() interface{}
// remove/return element Len()-1!
}!
!
// Note that Push and Pop in this interface are for !
// package heap's implementation to call. To add and !
// remove things from the heap, use heap.Push and!
// heap.Pop.!

www.cloudflare.com!
container/heap!
•  Simple example
type OrderedInts []int!
!
func (h OrderedInts) Len() int { return len(h) }!
func (h OrderedInts) Less(i, j int) bool {!
return h[i] < h[j]!
}!
func (h OrderedInts) Swap(i,j int) {h[i],h[j]=h[j],h[i]}!
func (h *OrderedInts) Push(x interface{}) {!
!*h = append(*h, x.(int))!
}!
func (h *OrderedInts) Pop() interface{} {!
!old := *h!
!n := len(old)-1!
!x := old[n]!
!*h = old[:n]!
!return x!
}!
www.cloudflare.com!
container/heap!
•  Using a heap
h := &OrderedInts{33,76,55,24,48,63,86,83,83,12}!
!
heap.Init(h)!
!
fmt.Printf("min: %dn", (*h)[0])!
!
for h.Len() > 0 {!
fmt.Printf("%d ", heap.Pop(h))!
}!
!
fmt.Printf(“n”)!

www.cloudflare.com!
container/heap!
•  Heaps are useful for...
•  Make a priority queue
•  Sorting
•  Graph algorithms

www.cloudflare.com!
MAP

www.cloudflare.com!
map!
•  Maps are typed



dictionary := make(map[string]string)!
dictionary := map[string]string{}!
!

•  They are not concurrency safe
•  Use a lock or channel for concurrent read/write access
counts := struct{!
sync.RWMutex!
m map[string]int!
}{m: make(map[string]int)}!
!
counts.RLock()!
fmt.Printf(“foo count”, counts.m[“foo”]!
counts.RUnlock()!
!
counts.Lock()!
counts.m[“foo”] += num_foos!
counts.Unlock()!
!
www.cloudflare.com!

Mul4ple	
  readers,	
  
one	
  writer	
  
map iteration
m := map[string]int{!
"bar”: 54,!
"foo”: 42,!
"baz”: -1,!
}!
!
for k := range m {!
// k is foo, bar, baz!
}!
!
for _, v := range m {!
// v is 54, 42, -1 in some order!
}!
!
for k, v := range m {!
// k and v are as above!
}!

www.cloudflare.com!

Order	
  of	
  itera4on	
  is	
  
undefined	
  	
  
Common map operations
•  Remove an element
delete(dictionary, “twerking”)!

•  Test presence of an element
definition, present := dictionary[“hoopy”]!
!
_, present := dictionary[“sigil”]!

•  Missing element gives a “zero” value




fmt.Printf(“[%s]n”, dictionary[“ewyfgwyegfweygf”])!
!
[]!

www.cloudflare.com!
SLICE

www.cloudflare.com!
Slices
•  A slice is part of an array
var arrayOfInts [256]int!
!
var part []int = arrayOfInts[2:6]!

•  arrayOfInts is 256 ints contiguously in memory
0	
  

1	
  

2	
  

3	
  

4	
  

5	
  

6	
  

7	
  

8	
  

9	
  

10	
  

11	
  

12	
  

!
!
•  part consists of a pointer (to arrayOfInts[2]) and a
length (4)

www.cloudflare.com!
Slice passing
•  A slice is passed (like everything else) by copy
var arrayOfInts [256]int!
!
var part []int = arrayOfInts[2:6]!
!
func fill(s []int) {!
for i, _ := range s {!
s[i] = i*2!
}!
!
s = s[1:]!
}!
Does	
  nothing	
  to	
  
!
part!
fill(part)!
fmt.Printf(“%#v”, part)!
!
% ./slice!
[]int{0, 2, 4, 6}!
www.cloudflare.com!

Contents	
  of	
  s	
  can	
  be	
  
modified	
  

Changes	
  contents	
  of	
  
underlying	
  array	
  
Slice passing, part 2
•  Can pass a pointer to a slice to modify the slice
var arrayOfInts [256]int!
!
var part intSlice = arrayOfInts[2:6] !
!
Contents	
  of	
  s	
  can	
  be	
  
type intSlice []int!
modified	
  and	
  s	
  can	
  
func (s *intSlice) fill() {!
be	
  changed	
  
for i, _ := range *s {!
(*s)[i] = i*2!
}!
*s = (*s)[1:]!
Changes	
  part!
}!
!
part.fill()!
fmt.Printf("%#vn", part)!
!
% ./slice!
[]int{2, 4, 6}!
www.cloudflare.com!
Slice iteration
prime := []int{2, 3, 5, 7, 11}!
!
for i := range prime {!
// i is 0, 1, 2, 3, 4!
}!
!
for _, e := range prime{!
// e is 2, 3, 5, 7, 11!
}!
!
for i, e := range prime {!
// i and e as above!
}!

www.cloudflare.com!
Copying slices
•  copy builtin
morePrimes := make([]int, len(primes), 2*cap(primes))!
!
copy(morePrimes, primes)!

•  copy allows source and destination to overlap
primes := [10]int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}!
odds := primes[1:7]!
!
odds = odds[0:len(odds)+1]!
copy(odds[4:], odds[3:])!
odds[3] = 9!
fmt.Printf("%#vn", odds)!
!
[]int{3, 5, 7, 9, 11, 13, 17}!

www.cloudflare.com!
Appending slices
s := []int{1, 3, 6, 10}!
t := []int{36, 45, 55, 66, 78}!
!
s = append(s, 15)!
Adding	
  individual	
  
elements	
  
s = append(s, 21, 28)!
!
s = append(s, t...)!
!
Adding	
  an	
  en4re	
  
nu := append([]int(nil), s...)!
slice	
  
!
s = append(s, s...)!
Copying	
  a	
  slice	
  (use	
  
!
copy	
  instead)	
  
fmt.Printf(“%#vn”, s)!
!
[]int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 1, 3,
6, 10, 15, 21, 28, 36, 45, 55, 66, 78}!

www.cloudflare.com!
CHANNELS AS QUEUES

www.cloudflare.com!
A buffered channel is a FIFO queue 
•  A typed queue of up to 10 Things



queue := make(chan Thing, 10)

!

•  Get the next element from the queue if there is one



select {!
case t := <-queue: // got one!
default:
// queue is empty!
}
!

•  Add to queue if there’s room
select {!
case queue <- t: // added to queue!
default:
// queue is full!
}!

www.cloudflare.com!
GENERICS

www.cloudflare.com!
Perhaps heretical
•  But... I wish Go had some generics
•  interface{} is like void *; Type assertions similar to casts
l := list.New()!
l.PushFront("Hello, World!")!
v := l.Front()!
i := v.Value.(int)!
% go build l.go!
% ./l!
panic: interface conversion: interface is
string, not int!
!
goroutine 1 [running]:!
runtime.panic(0x49bdc0, 0xc210041000)!
!/extra/go/src/pkg/runtime/panic.c:266
+0xb6!
main.main()!
!/extra/src/mc/generic.go:12 +0xaa!
www.cloudflare.com!
Sources etc.
•  Slides and code samples for this talk:

https://github.com/cloudflare/jgc-talks/tree/master/
Go_London_User_Group/Go_Containers

•  All my talks (with data/code) on the CloudFlare Github

https://github.com/cloudflare/jgc-talks
•  All my talks on the CloudFlare SlideShare

http://www.slideshare.net/cloudflare

www.cloudflare.com!

More Related Content

PDF
Go Concurrency
PDF
Go memory
PDF
Golang Channels
PDF
Goroutines and Channels in practice
PDF
Go Memory
PDF
Go Profiling - John Graham-Cumming
PDF
Go debugging and troubleshooting tips - from real life lessons at SignalFx
PDF
Concurrency in Golang
Go Concurrency
Go memory
Golang Channels
Goroutines and Channels in practice
Go Memory
Go Profiling - John Graham-Cumming
Go debugging and troubleshooting tips - from real life lessons at SignalFx
Concurrency in Golang

What's hot (20)

PDF
Go Concurrency
PDF
node ffi
PDF
Rubinius @ RubyAndRails2010
PDF
An Introduction to Go
PDF
Something about Golang
PDF
PyCon KR 2019 sprint - RustPython by example
PDF
Rcpp11 genentech
PDF
Python Coroutines, Present and Future
PPTX
All you need to know about the JavaScript event loop
PDF
R/C++ talk at earl 2014
PDF
Docopt
PDF
Introduction to kotlin coroutines
PPTX
Naughty And Nice Bash Features
PDF
When RegEx is not enough
PDF
Happy Go Programming
PDF
Python meetup: coroutines, event loops, and non-blocking I/O
PDF
Python Async IO Horizon
PDF
PyCon lightning talk on my Toro module for Tornado
PPTX
2015 555 kharchenko_ppt
PDF
Kotlin Coroutines. Flow is coming
Go Concurrency
node ffi
Rubinius @ RubyAndRails2010
An Introduction to Go
Something about Golang
PyCon KR 2019 sprint - RustPython by example
Rcpp11 genentech
Python Coroutines, Present and Future
All you need to know about the JavaScript event loop
R/C++ talk at earl 2014
Docopt
Introduction to kotlin coroutines
Naughty And Nice Bash Features
When RegEx is not enough
Happy Go Programming
Python meetup: coroutines, event loops, and non-blocking I/O
Python Async IO Horizon
PyCon lightning talk on my Toro module for Tornado
2015 555 kharchenko_ppt
Kotlin Coroutines. Flow is coming
Ad

Similar to Go Containers (20)

PDF
JVMLS 2016. Coroutines in Kotlin
PDF
Combinator parsing
PDF
Are we ready to Go?
PDF
JDD2014: GO! The one language you have to try in 2014 - Andrzej Grzesik
PDF
Go, the one language to learn in 2014
PPTX
Python language data types
PPTX
Python language data types
PPTX
Python language data types
PPTX
Python language data types
PPTX
Python language data types
PPTX
Python language data types
PPTX
Python language data types
PDF
Introduction to programming - class 11
PPT
go.ppt
PDF
Abstracting Vector Architectures in Library Generators: Case Study Convolutio...
PDF
Ruslan.shevchenko: most functional-day-kiev 2014
PDF
Learn You a Functional JavaScript for Great Good
PDF
Music as data
PDF
Go: It's Not Just For Google
PDF
ECMAScript 6
JVMLS 2016. Coroutines in Kotlin
Combinator parsing
Are we ready to Go?
JDD2014: GO! The one language you have to try in 2014 - Andrzej Grzesik
Go, the one language to learn in 2014
Python language data types
Python language data types
Python language data types
Python language data types
Python language data types
Python language data types
Python language data types
Introduction to programming - class 11
go.ppt
Abstracting Vector Architectures in Library Generators: Case Study Convolutio...
Ruslan.shevchenko: most functional-day-kiev 2014
Learn You a Functional JavaScript for Great Good
Music as data
Go: It's Not Just For Google
ECMAScript 6
Ad

More from jgrahamc (9)

PPTX
Better living through microcontrollers
PDF
Big O London Meetup April 2015
PDF
How to launch and defend against a DDoS
PPTX
Lua: the world's most infuriating language
PPTX
Software Debugging for High-altitude Balloons
PDF
Highlights of Go 1.1
PPTX
That'll never work!
PPTX
HAB Software Woes
PPTX
Javascript Security
Better living through microcontrollers
Big O London Meetup April 2015
How to launch and defend against a DDoS
Lua: the world's most infuriating language
Software Debugging for High-altitude Balloons
Highlights of Go 1.1
That'll never work!
HAB Software Woes
Javascript Security

Recently uploaded (20)

PDF
Machine learning based COVID-19 study performance prediction
PDF
KodekX | Application Modernization Development
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PPTX
Big Data Technologies - Introduction.pptx
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
NewMind AI Monthly Chronicles - July 2025
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
Machine learning based COVID-19 study performance prediction
KodekX | Application Modernization Development
“AI and Expert System Decision Support & Business Intelligence Systems”
Spectral efficient network and resource selection model in 5G networks
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Big Data Technologies - Introduction.pptx
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Digital-Transformation-Roadmap-for-Companies.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Review of recent advances in non-invasive hemoglobin estimation
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
Building Integrated photovoltaic BIPV_UPV.pdf
Electronic commerce courselecture one. Pdf
Encapsulation_ Review paper, used for researhc scholars
Advanced methodologies resolving dimensionality complications for autism neur...
NewMind AI Monthly Chronicles - July 2025
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Mobile App Security Testing_ A Comprehensive Guide.pdf
20250228 LYD VKU AI Blended-Learning.pptx

Go Containers

  • 1. Go Containers January 23, 2014 John Graham-Cumming www.cloudflare.com!
  • 2. Six interesting containers •  From pkg/container! •  container/list! •  container/ring! •  container/heap
 ! •  Built in •  map! •  slice •  Channels as queues www.cloudflare.com!
  • 3. container/list! •  Doubly-linked list implementation •  Uses interface{} for values l := list.New()! e0 := l.PushBack(42)! e1 := l.PushFront(13)! Pity  there’s  no  ‘map’   e2 := l.PushBack(7)! func4on   l.InsertBefore(3, e0)! l.InsertAfter(196, e1)! l.InsertAfter(1729, e2)! ! for e := l.Front(); e != nil; e = e.Next() {! fmt.Printf("%d ", e.Value.(int))! }! e.Value  to  get  the   fmt.Printf("n")! stored  value   ! ! 13 196 3 42 7 1729! www.cloudflare.com!
  • 4. container/list! All  work  on   elements  not  values     l.MoveToFront(e2)! l.MoveToBack(e1)! Returns  the  value   l.Remove(e0)! removed   ! for e := l.Front(); e != nil; e = e.Next() {! fmt.Printf("%d ", e.Value.(int))! }! fmt.Printf("n")! ! ! 7 196 3 1729 13! www.cloudflare.com!
  • 5. container/ring! •  A circular ‘list’ parus := []string{”major", “holsti”, “carpi”}! ! r := ring.New(len(parus))! for i := 0; i < r.Len(); i++ {! r.Value = parus[i]! r = r.Next()! }! ! r.Do(func(x interface{}) {! fmt.Printf(“Parus %sn”, x.(string))! })! •  Move n elements through ring r.Move(n)! www.cloudflare.com!
  • 6. container/heap! •  Implements a “min-heap” (i.e. tree where each node is the “minimum” element in its subtree) •  Needs a notion of “Less” and a way to “Swap” www.cloudflare.com!
  • 7. container/heap! •  The single most confusing definition in all of Go type Interface interface {! sort.Interface! Push(x interface{}) // add x as element Len()! Pop() interface{} // remove/return element Len()-1! }! ! // Note that Push and Pop in this interface are for ! // package heap's implementation to call. To add and ! // remove things from the heap, use heap.Push and! // heap.Pop.! www.cloudflare.com!
  • 8. container/heap! •  Simple example type OrderedInts []int! ! func (h OrderedInts) Len() int { return len(h) }! func (h OrderedInts) Less(i, j int) bool {! return h[i] < h[j]! }! func (h OrderedInts) Swap(i,j int) {h[i],h[j]=h[j],h[i]}! func (h *OrderedInts) Push(x interface{}) {! !*h = append(*h, x.(int))! }! func (h *OrderedInts) Pop() interface{} {! !old := *h! !n := len(old)-1! !x := old[n]! !*h = old[:n]! !return x! }! www.cloudflare.com!
  • 9. container/heap! •  Using a heap h := &OrderedInts{33,76,55,24,48,63,86,83,83,12}! ! heap.Init(h)! ! fmt.Printf("min: %dn", (*h)[0])! ! for h.Len() > 0 {! fmt.Printf("%d ", heap.Pop(h))! }! ! fmt.Printf(“n”)! www.cloudflare.com!
  • 10. container/heap! •  Heaps are useful for... •  Make a priority queue •  Sorting •  Graph algorithms www.cloudflare.com!
  • 12. map! •  Maps are typed dictionary := make(map[string]string)! dictionary := map[string]string{}! ! •  They are not concurrency safe •  Use a lock or channel for concurrent read/write access counts := struct{! sync.RWMutex! m map[string]int! }{m: make(map[string]int)}! ! counts.RLock()! fmt.Printf(“foo count”, counts.m[“foo”]! counts.RUnlock()! ! counts.Lock()! counts.m[“foo”] += num_foos! counts.Unlock()! ! www.cloudflare.com! Mul4ple  readers,   one  writer  
  • 13. map iteration m := map[string]int{! "bar”: 54,! "foo”: 42,! "baz”: -1,! }! ! for k := range m {! // k is foo, bar, baz! }! ! for _, v := range m {! // v is 54, 42, -1 in some order! }! ! for k, v := range m {! // k and v are as above! }! www.cloudflare.com! Order  of  itera4on  is   undefined    
  • 14. Common map operations •  Remove an element delete(dictionary, “twerking”)! •  Test presence of an element definition, present := dictionary[“hoopy”]! ! _, present := dictionary[“sigil”]! •  Missing element gives a “zero” value fmt.Printf(“[%s]n”, dictionary[“ewyfgwyegfweygf”])! ! []! www.cloudflare.com!
  • 16. Slices •  A slice is part of an array var arrayOfInts [256]int! ! var part []int = arrayOfInts[2:6]! •  arrayOfInts is 256 ints contiguously in memory 0   1   2   3   4   5   6   7   8   9   10   11   12   ! ! •  part consists of a pointer (to arrayOfInts[2]) and a length (4) www.cloudflare.com!
  • 17. Slice passing •  A slice is passed (like everything else) by copy var arrayOfInts [256]int! ! var part []int = arrayOfInts[2:6]! ! func fill(s []int) {! for i, _ := range s {! s[i] = i*2! }! ! s = s[1:]! }! Does  nothing  to   ! part! fill(part)! fmt.Printf(“%#v”, part)! ! % ./slice! []int{0, 2, 4, 6}! www.cloudflare.com! Contents  of  s  can  be   modified   Changes  contents  of   underlying  array  
  • 18. Slice passing, part 2 •  Can pass a pointer to a slice to modify the slice var arrayOfInts [256]int! ! var part intSlice = arrayOfInts[2:6] ! ! Contents  of  s  can  be   type intSlice []int! modified  and  s  can   func (s *intSlice) fill() {! be  changed   for i, _ := range *s {! (*s)[i] = i*2! }! *s = (*s)[1:]! Changes  part! }! ! part.fill()! fmt.Printf("%#vn", part)! ! % ./slice! []int{2, 4, 6}! www.cloudflare.com!
  • 19. Slice iteration prime := []int{2, 3, 5, 7, 11}! ! for i := range prime {! // i is 0, 1, 2, 3, 4! }! ! for _, e := range prime{! // e is 2, 3, 5, 7, 11! }! ! for i, e := range prime {! // i and e as above! }! www.cloudflare.com!
  • 20. Copying slices •  copy builtin morePrimes := make([]int, len(primes), 2*cap(primes))! ! copy(morePrimes, primes)! •  copy allows source and destination to overlap primes := [10]int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}! odds := primes[1:7]! ! odds = odds[0:len(odds)+1]! copy(odds[4:], odds[3:])! odds[3] = 9! fmt.Printf("%#vn", odds)! ! []int{3, 5, 7, 9, 11, 13, 17}! www.cloudflare.com!
  • 21. Appending slices s := []int{1, 3, 6, 10}! t := []int{36, 45, 55, 66, 78}! ! s = append(s, 15)! Adding  individual   elements   s = append(s, 21, 28)! ! s = append(s, t...)! ! Adding  an  en4re   nu := append([]int(nil), s...)! slice   ! s = append(s, s...)! Copying  a  slice  (use   ! copy  instead)   fmt.Printf(“%#vn”, s)! ! []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78}! www.cloudflare.com!
  • 23. A buffered channel is a FIFO queue •  A typed queue of up to 10 Things queue := make(chan Thing, 10) ! •  Get the next element from the queue if there is one select {! case t := <-queue: // got one! default: // queue is empty! } ! •  Add to queue if there’s room select {! case queue <- t: // added to queue! default: // queue is full! }! www.cloudflare.com!
  • 25. Perhaps heretical •  But... I wish Go had some generics •  interface{} is like void *; Type assertions similar to casts l := list.New()! l.PushFront("Hello, World!")! v := l.Front()! i := v.Value.(int)! % go build l.go! % ./l! panic: interface conversion: interface is string, not int! ! goroutine 1 [running]:! runtime.panic(0x49bdc0, 0xc210041000)! !/extra/go/src/pkg/runtime/panic.c:266 +0xb6! main.main()! !/extra/src/mc/generic.go:12 +0xaa! www.cloudflare.com!
  • 26. Sources etc. •  Slides and code samples for this talk: https://github.com/cloudflare/jgc-talks/tree/master/ Go_London_User_Group/Go_Containers •  All my talks (with data/code) on the CloudFlare Github https://github.com/cloudflare/jgc-talks •  All my talks on the CloudFlare SlideShare http://www.slideshare.net/cloudflare www.cloudflare.com!