Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
go doSomeThing()
Search
Jérémy Courtial
February 24, 2016
Programming
0
49
go doSomeThing()
Jérémy Courtial
February 24, 2016
Tweet
Share
More Decks by Jérémy Courtial
See All by Jérémy Courtial
sudo give the cloud
mrartichaut
0
23
An introduction to AppSec?
mrartichaut
0
36
Secure by design: introduction to threat modeling
mrartichaut
0
39
Taming secrets with Vault
mrartichaut
0
73
Lead Tech: Empowering the team
mrartichaut
0
43
Web Platform Security
mrartichaut
0
43
Practical Cryptography : Data Encryption
mrartichaut
0
55
Practical Cryptography : Password Hashing
mrartichaut
1
65
HTTP/2 : One connection to rule them all
mrartichaut
1
55
Other Decks in Programming
See All in Programming
Exploring the Implementation of “t.Run”, “t.Parallel”, and “t.Cleanup”
akarin
1
100
Goのエラースタックトレースの歴史と今後
sonatard
9
1.7k
Let's learn code review
riofujimon
2
560
Snowflakeで眠ったデータを起こそう!
estie
0
130
Milestoner
bkuhlmann
1
410
Implementing Design Systems in Swift
seyfoyun
0
370
冗長なエラーログを削減し、スタックトレースを手に入れる / Reducing Verbose Error Logs and Obtaining Stack Traces
upamune
0
960
Build Apps for iOS, Android & Desktop in 100% Kotlin With Compose Multiplatform (mDevCamp 2024)
zsmb
0
420
サイコロで理解する統計的仮説検定の考え方
tatamiya
4
1k
Micro Frontends for Java Microservices - Utah JUG 2024
mraible
PRO
1
100
新宿ダンジョンを可視化してみた
satoshi7190
2
280
SIMD Parallel Programming with the Vector API
josepaumard
0
220
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
44
6.8k
Making Projects Easy
brettharned
109
5.5k
KATA
mclloyd
16
12k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
228
16k
How to name files
jennybc
65
93k
Facilitating Awesome Meetings
lara
43
5.6k
A better future with KSS
kneath
231
16k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
11
1.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
222
21k
In The Pink: A Labor of Love
frogandcode
138
21k
How GitHub Uses GitHub to Build GitHub
holman
468
290k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
33
6k
Transcript
go doSomething() author := "Jérémy Courtial"
// Pragmatic & productive // language for efficient // softwares
type GoLang struct { … }
go.creationYear = "2007" go.authors = []Author{ "Robert Griesemer", "Rob Pike",
"Ken Thompson"}
go.users = []Company{ "Google", "Docker" "SoundCloud", "Dropbox", "Facebook", "CoreOS", "Cloudflare",
… }
go := Language{ memManagement: gc, packaging: fatBinary, crossPlatform: true
…
… paradigm: imperative, typeSystem: static-inferred, licence: openSource }
import "fmt"
import "fmt" func main() { }
import "fmt" func main() { msg := "Hello, World" }
import "fmt" func main() { msg := "Hello, World" fmt.Println(msg)
}
// Go has interface type Human interface { SayHello() }
// Struct is a class equiv. type HomoSapiens struct {
Name string Age int }
func (hs HomoSapiens) SayHello { }
func (hs HomoSapiens) SayHello { fmt.Println("Hi, i'm", hs.Name) }
// Now HomoSapiens implements Human func (hs HomoSapiens) SayHello {
fmt.Println("Hi, i'm", hs.Name) }
/* "Favor 'object composition' over 'class inheritance'." Design Patterns, GoF,
1995 */
type Robot interface { DestroyHumanity() }
type Cyborg struct { Human Robot gadgets []Gadget }
t800 := Cyborg { }
t800 := Cyborg { human: HumanImpl{}, }
t800 := Cyborg { human: HumanImpl{}, robot: RobotImpl{}, }
t800 := Cyborg { human: HumanImpl{}, robot: RobotImpl{}, gadgets: lethalGadgets,
}
t800.SayHello() t800.DestroyHumanity()
// golang.org/doc/effective_go.html
go.missings = []Feature{ }
go.missings = []Feature{ "Generics", }
go.missings = []Feature{ "Generics", "Pointer Arithmetic", }
go.missings = []Feature{ "Generics", "Pointer Arithmetic", "try/catch", }
go.missings = []Feature{ "Generics", "Pointer Arithmetic", "try/catch", "Implicit Conversions"}
go.tools = []Tool{ "go build", "go fmt", "go get", "go
vet", … }
go.stdLib = []Package{ "net/http", "crypto/aes", "encoding/json", "sort", "bytes", "compress/gzip", "image/png",
"net/html", … }
func NewCipher(key []byte) (cipher.Block, error) type Block interface {
BlockSize() int Encrypt(dst, src []byte) Decrypt(dst, src []byte) }
func main() { http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request ) {
msg := map[string]string {"msg": "Hello, World!"} j, _ := json.Marshal(msg) w.Write(j) }) http.ListenAndServe(":8080", nil) }
go.concurrency = LigthAndFastImpl{}
go doSomthingForAWhile()
/* Don't communicate by sharing, share by communicating. */
// Instanciates a channel of strings c := make(chan string)
go work(c)
func work(c chan string) { }
func work(c chan string) { for { } }
func work(c chan string) { for { msg := <-
c } }
func work(c chan string) { for { msg := <-
c fmt.Println(msg) } }
c <- "Hello World!" time.Sleep(5) c <- "Have a nice
day!" time.Sleep(5) c <- "Bye bye!"
func work(quit, c chan int) { }
func work(quit, c chan int) { select { } }
func work(quit, c chan int) { select { case n
:= <- c : } }
func work(quit, c chan int) { select { case n
:= <- c : process(n) } }
func work(quit, c chan int) { select { case n
:= <- c : process(n) case <- quit : } }
func work(quit, c chan int) { select { case n
:= <- c : process(n) case <- quit : return } }
// Why Go's concurrency is special ?
define("C10k problem")
// Most evident tool type Thread struct { … }
/* Be naive : One thread per connection */
for { }
for { conn := tcp.accept() }
for { conn := tcp.accept() newThread() }
for { conn := tcp.accept() newThread().run( func() { }) }
for { conn := tcp.accept() newThread().run( func() { handleConnection(conn) })
}
#BEGIN JAVA #END JAVA // Quick & dirty POC
#BEGIN JAVA #END JAVA while (true) { } // Quick
& dirty POC
#BEGIN JAVA #END JAVA while (true) { new Thread(() ->
{ }); } // Quick & dirty POC
#BEGIN JAVA #END JAVA while (true) { new Thread(() ->
{ sleep(Long.MAX_VALUE); }); } // Quick & dirty POC
#BEGIN JAVA #END JAVA while (true) { new Thread(() ->
{ sleep(Long.MAX_VALUE); }); } // What will happen ?
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native
thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:714) at Test.main(Test.java:19) $ javac Test.java && java Test
/* - Each thread has is own stack - Stack's
size is hard to predict => alloc ~1 Mo per thread */
|- — — — — — — - - -
- -| | Thread Stack 1 | |- - - - - - - - - - - -| | . | | . | | . | | . | | . | | . | | . | | . | | . | |_ _ _ _ _ _ _ _ _ _ _ _|
|- — — — — — — - - -
- -| | Thread Stack 1 | |- - - - - - - - - - - -| | Guard Page | | — — — — — — — - - - - | | . | | . | | . | | . | | . | | . | | . | |_ _ _ _ _ _ _ _ _ _ _ _|
|- — — — — — — - - -
- -| | Thread Stack 1 | |- - - - - - - - - - - -| | Guard Page | | — — — — — — — - - - - | | Thread Stack 2 | |- - - - - - - - - - - -| | . | | . | | . | | . | | . | |_ _ _ _ _ _ _ _ _ _ _ _|
|- — — — — — — - - -
- -| | Thread Stack 1 | |- - - - - - - - - - - -| | Guard Page | | — — — — — — — - - - - | | Thread Stack 2 | |- - - - - - - - - - - -| | Guard Page | |- - - - - - - - - - - -| | . | | . | | . | |_ _ _ _ _ _ _ _ _ _ _ _|
// Let's try something else … pool := NewThreadPool(n)
pool.submit(work)
work := func() { // Blocks until done … readFromNetwork()
}
if pool.hasAvailableThread == false { gameOver() }
// We need different tools IO.asynchronous = true
/* The Hollywood Principle : "Don't call us, we'll call
you" */
b := readFromNetwork() //Block here /* With synchronous I/O */
readFromNetwork(func(b []byte) { //Call when data are available }) /*
With asynchronous I/O */
// Let's try something else … type EventDriven struct {
… }
// Event Driven // Always use async I/O // Considers
I/O as events producers // Events are gathered by a loop
const ( NewConnectionEvent = 1 DataAvailableEvent = 2 DataSentEvent =
3 … )
type Event struct { type EventType callback func() result []byte
}
loop := NewEventLoop() thread.run(loop)
func (l loop) run() { }
func (l loop) run() { for { } }
func (l loop) run() { for { events := os.GatherEvents()
} }
func (l loop) run() { for { events := os.GatherEvents()
l.dispatch(events) } }
func (l loop) dispatch(e []Event) { }
func (l loop) dispatch(e []Event) { for event := range
e { } }
func (l loop) dispatch(e []Event) { for event := range
e { event.callback(e.result) } }
// Drawbacks
// Callbacks hells
s.onNewConnection(func(…){ … }).onDataAvailable(func(…){ … }) s.sendData(data, func(…){ … })
// Singled threaded // Bad for vertical scaling thread.run(loop)
// We need different tools
|- — — — — — — - - -
- -| | | | | | | | | | | |- - - - - - - - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | | | | | | | | | | |- - - - - - - - - - - -| | | | | | | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | | | | | | | | | | |- - - - - - - - - - - -| | | | | | Drivers | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | | | | | | | | | | |- - - - - - - - - - - -| | SysCall Interface | | | | Drivers | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | Applications | | | | | | | | | |- - - - - - - - - - - -| | SysCall Interface | | | | Drivers | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | Applications | | | | Daemons | | | | | |- - - - - - - - - - - -| | SysCall Interface | | | | Drivers | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | Applications | | | | Daemons | | | | Librairies | |- - - - - - - - - - - -| | SysCall Interface | | | | Drivers | | | | Process/Mem management| |_ _ _ _ _ _ _ _ _ _ _ _| // User space // Kernel Space
|- — — — — — — - - -
- -| | | | | | NewOSThread() | | | | | |- — — — — — — - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| // Kernel threads
|- — — — — — — - - -
- -| | | | | | NewOSThread() | | | | | | |- - - - - | - - - - - -| | ∨ | | | | kernel_thread(…) | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| // Kernel threads
|- — — — — — — - - -
- -| | | | User Thread 1 | | | | | | | |- — — — — — — - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| /* Users threads */
|- — — — — — — - - -
- -| | | | User Thread 1 | | User Thread 2 | | | | | |- — — — — — — - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| /* Users threads */
|- — — — — — — - - -
- -| | | | User Thread 1 | | User Thread 2 | | User Thread 3 | | | |- — — — — — — - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| /* Users threads */
|- — — — — — — - - -
- -| | — — — — — — — — | | | User Thread 1 | | | | User Thread 2 | | | | User Thread 3 | | | - - - - - - - - | |- — — — — — — - - - - -| | | | | | | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| /* Users threads */
|- — — — — — — - - -
- -| | — — — — — — — — | | | User Thread 1 | | | | User Thread 2 | | | | User Thread 3 | | | - - - | - - - - | |- - - - - | - - - - - -| | ∨ | | | | kernel_thread(…) | | | | | |_ _ _ _ _ _ _ _ _ _ _ _| /* Users threads N:M */
// User Threads // Cheaper than kernel threads // Backed
by one or more K threads // App is responsible for scheduling
goroutines == User threads
// Goroutines are // Cheap in memory : 2 Ko
only // Cheap to create/destroy // Cheap to switch
for { }
for { conn := tcp.accept() }
for { conn := tcp.accept() go handleConnection(conn) }
func handleConnection(c net.Conn){ }
func handleConnection(c net.Conn){ data := c.Read(4096) }
func handleConnection(c net.Conn){ data := c.Read(4096) response := process(data) }
func handleConnection(c net.Conn){ data := c.Read(4096) response := process(data) c.Write(response)
}
data := c.Read(4096)
data := c.Read(4096) // Blocks the goroutine until // data
are available
data := c.Read(4096) // But don't block the thread //
and other goroutines
// Goroutines scheduling // Scheduling is cooperative // Blocking IOs
used as switch point // When a gorountine blocks another // is wake up
/* Now you can be naive : One thread per
connection */ goroutine
/* The gopher way : Focus on what you want
to do */
// Let's go ?
// October 10, 2016 · PARIS
/* Bibliography golang.org tour.golang.org talks.golang.org */
/* Bibliography The Go scheduler How Goroutines work Performance Without
The Event Loop */
// Thanks // Questions ?