Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
Concurrency in Go (or, Erlang done right)
Programming Model <ul><li>Mostly CSP/π-calaculus (not actually formalized): goroutines+channels </li></ul><ul><li>Go concu...
Goroutines <ul><li>Think  threads  (however no  join  operation) </li></ul><ul><li>go  foo() </li></ul><ul><li>go  logger....
Channels <ul><li>Basically typed bounded blocking FIFO queues. </li></ul><ul><li>// synchronous chan of ints </li></ul><ul...
Channels: First-class citizens <ul><li>You can pass them as function arguments, store in containers, pass via channels, et...
Channels: input/output <ul><li>func foo(c chan int) { </li></ul><ul><li>   c <- 0 </li></ul><ul><li>   <-c </li></ul><ul><...
Channels: closing <ul><li>func producer(c chan *Work) { </li></ul><ul><li>    defer close(c) </li></ul><ul><li>    for { <...
Why no goroutine join? <ul><li>Usually it's required to return some result anyway. </li></ul><ul><li>   c := make(chan int...
Select <ul><li>Select makes a pseudo-random choice which of a set of possible communications will proceed: </li></ul><ul><...
Select: non-blocking send/recv <ul><li>reqChan := make(chan *Request,  100 ) </li></ul><ul><li>httpReq := parse() </li></u...
Select: timeouts <ul><li>select { </li></ul><ul><li>   case c <- foo: </li></ul><ul><li>   case  <-time.After(1e9) : </li>...
Example: Barber Shop <ul><li>var seats = make(chan Customer, 4) </li></ul><ul><li>func barber() { </li></ul><ul><li>   for...
Example: Resource Pooling <ul><li>Q: General pooling functionality Any has in their code somewhere, a good pooling mechani...
Example: Resource Pooling (cont) <ul><li>The solution is just </li></ul><ul><li>pool := make(chan *Resource, 100) </li></u...
Example: Actor-oriented programming <ul><li>type ReadReq struct { </li></ul><ul><li>   key string </li></ul><ul><li>   ack...
Example: Actor-oriented programming <ul><li>c <-  WriteReq {&quot;foo&quot;, &quot;bar&quot;} </li></ul><ul><li>ack := mak...
Example: Thread Pool <ul><li>[This page intentionally left blank] </li></ul>
Why does pure CSP suck? <ul><li>CSP-style memory allocation: </li></ul><ul><li>ack1 := make(chan *byte) </li></ul><ul><li>...
Why does pure CSP suck? <ul><li>Some application code is no different! </li></ul><ul><li>var UidReq = make(chan chan uint6...
Why does pure CSP suck? <ul><li>“ Message passing is easy to implement. But everything gets turned into distributed progra...
Shared Memory to the Rescue! <ul><li>var seq = uint64(0) </li></ul><ul><li>... </li></ul><ul><li>uid :=  atomic.AddUint64(...
Shared Memory Primitives <ul><li>sync.Mutex </li></ul><ul><li>sync.RWMutex </li></ul><ul><li>sync.Cond </li></ul><ul><li>s...
Mutexes <ul><li>sync.Mutex is actually a cooperative binary semaphore - no ownership, no recursion. </li></ul><ul><li>mtx....
General Scheme <ul><li>90% of CSP on higher levels </li></ul><ul><li>+10% of Shared Memory on lower levels </li></ul><ul><...
Race Detector for Go <ul><li>Currently under development in Google MSK (no obligations to deliver at this stage). </li></u...
Scalability <ul><li>The goal of Go is to support scalable fine-grained concurrency. But it is [was] not yet there. </li></...
  <ul><li>Thanks! </li></ul>
Nächste SlideShare
Wird geladen in …5
×

Concurrency in go

3.212 Aufrufe

Veröffentlicht am

Concurrency in go
From: https://docs.google.com/present/view?id=df36r82q_5gdq5gzth&pli=1

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Concurrency in go

  1. 1. Concurrency in Go (or, Erlang done right)
  2. 2. Programming Model <ul><li>Mostly CSP/π-calaculus (not actually formalized): goroutines+channels </li></ul><ul><li>Go concurrency motto: </li></ul><ul><li>&quot;Do not communicate by sharing memory; instead, share memory by communicating&quot; </li></ul><ul><li>+ Full-fledged shared memory </li></ul>
  3. 3. Goroutines <ul><li>Think threads (however no join operation) </li></ul><ul><li>go foo() </li></ul><ul><li>go logger.Printf(&quot;Hello, %s!&quot;, who) </li></ul><ul><li>go func() { </li></ul><ul><li>     logger.Printf(&quot;Hello, %s!&quot;, who) </li></ul><ul><li>    ... }() </li></ul>
  4. 4. Channels <ul><li>Basically typed bounded blocking FIFO queues. </li></ul><ul><li>// synchronous chan of ints </li></ul><ul><li>c := make(chan int) </li></ul><ul><li>// buffered chan of pointers to Request </li></ul><ul><li>c := make(chan *Request, 100)  </li></ul>
  5. 5. Channels: First-class citizens <ul><li>You can pass them as function arguments, store in containers, pass via channels, etc. </li></ul><ul><li>Moreover, channels are not tied to goroutines. Several goroutines can send/recv from a single channel. </li></ul>
  6. 6. Channels: input/output <ul><li>func foo(c chan int) { </li></ul><ul><li>  c <- 0 </li></ul><ul><li>  <-c </li></ul><ul><li>} </li></ul><ul><li>func bar(c <-chan int) { </li></ul><ul><li>  <-c </li></ul><ul><li>} </li></ul><ul><li>func baz(c chan<- int) { </li></ul><ul><li>  c <- 0 </li></ul><ul><li>} </li></ul>
  7. 7. Channels: closing <ul><li>func producer(c chan *Work) { </li></ul><ul><li>    defer close(c) </li></ul><ul><li>    for { </li></ul><ul><li>        work, ok := getWork() </li></ul><ul><li>        if !ok { return } </li></ul><ul><li>        c <- work </li></ul><ul><li>    } </li></ul><ul><li>} </li></ul><ul><li>// consumer </li></ul><ul><li>for msg := range c { </li></ul><ul><li>    process(msg) </li></ul><ul><li>} </li></ul>
  8. 8. Why no goroutine join? <ul><li>Usually it's required to return some result anyway. </li></ul><ul><li>  c := make(chan int, N) </li></ul><ul><li>  // fork </li></ul><ul><li>  for i := 0; i < N; i++ { </li></ul><ul><li>    go func() { </li></ul><ul><li>      result := ... </li></ul><ul><li>      c <- result </li></ul><ul><li>    }() </li></ul><ul><li>  } </li></ul><ul><li>  // join </li></ul><ul><li>  sum := 0 </li></ul><ul><li>  for i := 0; i < N; i++ { </li></ul><ul><li>    sum += <-c </li></ul><ul><li>  } </li></ul>
  9. 9. Select <ul><li>Select makes a pseudo-random choice which of a set of possible communications will proceed: </li></ul><ul><li>select {   case c1 <- foo: </li></ul><ul><li>  case m := <-c2: </li></ul><ul><li>    doSomething(m) </li></ul><ul><li>  case m := <-c3: </li></ul><ul><li>    doSomethingElse(m) </li></ul><ul><li>  default: </li></ul><ul><li>    doDefault() </li></ul><ul><li>} </li></ul>
  10. 10. Select: non-blocking send/recv <ul><li>reqChan := make(chan *Request, 100 ) </li></ul><ul><li>httpReq := parse() </li></ul><ul><li>select { </li></ul><ul><li>  case reqChan <- httpReq: </li></ul><ul><li>  default : </li></ul><ul><li>    reply(httpReq, 503) </li></ul><ul><li>} </li></ul>
  11. 11. Select: timeouts <ul><li>select { </li></ul><ul><li>  case c <- foo: </li></ul><ul><li>  case <-time.After(1e9) : </li></ul><ul><li>} </li></ul>
  12. 12. Example: Barber Shop <ul><li>var seats = make(chan Customer, 4) </li></ul><ul><li>func barber() { </li></ul><ul><li>  for { </li></ul><ul><li>    c := <-seats </li></ul><ul><li>    // shave c </li></ul><ul><li>  } </li></ul><ul><li>} </li></ul><ul><li>go barber() </li></ul><ul><li>func (c Customer) shave() { </li></ul><ul><li>  select { </li></ul><ul><li>  case seats <- c: </li></ul><ul><li>  default: </li></ul><ul><li>  } </li></ul><ul><li>} </li></ul><ul><li>It is that simple! </li></ul>
  13. 13. Example: Resource Pooling <ul><li>Q: General pooling functionality Any has in their code somewhere, a good pooling mechanism for interface type maybe? Or just somthing one could adapt and abstract? I'm sure some db drivers should have this, any ideas? </li></ul><ul><li>Sounds a bit frightening... </li></ul>
  14. 14. Example: Resource Pooling (cont) <ul><li>The solution is just </li></ul><ul><li>pool := make(chan *Resource, 100) </li></ul><ul><li>Put with [nonblocking] send. </li></ul><ul><li>Get with [nonblocking] recv. </li></ul><ul><li>It is that simple! </li></ul><ul><li>Haa, works like a charm. Go  makes things so nice and simple, yet so powerful! Thanks </li></ul>
  15. 15. Example: Actor-oriented programming <ul><li>type ReadReq struct { </li></ul><ul><li>  key string </li></ul><ul><li>  ack chan<- string </li></ul><ul><li>} </li></ul><ul><li>type WriteReq struct { </li></ul><ul><li>  key, val string </li></ul><ul><li>} </li></ul><ul><li>c := make(chan interface{} ) </li></ul><ul><li>go func() { </li></ul><ul><li>  m := make(map[string]string) </li></ul><ul><li>  for { </li></ul><ul><li>    switch r := (<-c).(type) { </li></ul><ul><li>    case ReadReq: </li></ul><ul><li>      r.ack <- m[r.key] </li></ul><ul><li>    case WriteReq: </li></ul><ul><li>      m[r.key] = r.val </li></ul><ul><li>    } </li></ul><ul><li>  } </li></ul><ul><li>}() </li></ul>
  16. 16. Example: Actor-oriented programming <ul><li>c <- WriteReq {&quot;foo&quot;, &quot;bar&quot;} </li></ul><ul><li>ack := make(chan string) </li></ul><ul><li>c <- ReadReq {&quot;foo&quot;, ack} </li></ul><ul><li>fmt.Printf(&quot;Got&quot;, <-ack) </li></ul><ul><li>It is that simple! </li></ul>
  17. 17. Example: Thread Pool <ul><li>[This page intentionally left blank] </li></ul>
  18. 18. Why does pure CSP suck? <ul><li>CSP-style memory allocation: </li></ul><ul><li>ack1 := make(chan *byte) </li></ul><ul><li>Malloc <- AllocReq{10, ack1} </li></ul><ul><li>ack2 := make(chan *byte) </li></ul><ul><li>Malloc <- AllocReq{20, ack2} </li></ul><ul><li>obj1 := <-ack1 </li></ul><ul><li>obj2 := <-ack2 </li></ul><ul><li>WTF??1! </li></ul>
  19. 19. Why does pure CSP suck? <ul><li>Some application code is no different! </li></ul><ul><li>var UidReq = make(chan chan uint64) </li></ul><ul><li>go func() { </li></ul><ul><li>  seq := uint64(0) </li></ul><ul><li>  for { </li></ul><ul><li>    c := <-UidReq </li></ul><ul><li>    c <- seq </li></ul><ul><li>    seq++ </li></ul><ul><li>  } </li></ul><ul><li>}() </li></ul><ul><li>ack := make(chan uint64) </li></ul><ul><li>UidReq <- ack </li></ul><ul><li>uid := <-ack </li></ul>
  20. 20. Why does pure CSP suck? <ul><li>“ Message passing is easy to implement. But everything gets turned into distributed programming then” (c) Joseph Seigh </li></ul><ul><li>- Additional overheads </li></ul><ul><li>- Additional latency </li></ul><ul><li>- Unnecessary complexity (asynchrony, reorderings) </li></ul><ul><li>- Load balancing </li></ul><ul><li>- Overload control </li></ul><ul><li>- Hard to debug </li></ul>
  21. 21. Shared Memory to the Rescue! <ul><li>var seq = uint64(0) </li></ul><ul><li>... </li></ul><ul><li>uid := atomic.AddUint64(&seq, 1) </li></ul><ul><li>Simple, fast, no additional latency, no bottlenecks, no overloads. </li></ul>
  22. 22. Shared Memory Primitives <ul><li>sync.Mutex </li></ul><ul><li>sync.RWMutex </li></ul><ul><li>sync.Cond </li></ul><ul><li>sync.Once </li></ul><ul><li>sync.WaitGroup </li></ul><ul><li>runtime.Semacquire/Semrelease </li></ul><ul><li>atomic.CompareAndSwap/Add/Load </li></ul>
  23. 23. Mutexes <ul><li>sync.Mutex is actually a cooperative binary semaphore - no ownership, no recursion. </li></ul><ul><li>mtx. Lock () </li></ul><ul><li>go func() { </li></ul><ul><li>    ... </li></ul><ul><li>    mtx. Unlock () } </li></ul><ul><li>mtx. Lock () </li></ul><ul><li>func foo() { </li></ul><ul><li>  mtx.Lock() </li></ul><ul><li>  defer mtx.Unlock() </li></ul><ul><li>  ... </li></ul><ul><li>} </li></ul>
  24. 24. General Scheme <ul><li>90% of CSP on higher levels </li></ul><ul><li>+10% of Shared Memory on lower levels </li></ul><ul><li>  </li></ul>
  25. 25. Race Detector for Go <ul><li>Currently under development in Google MSK (no obligations to deliver at this stage). </li></ul><ul><li>The idea is to provide general support for dynamic analysis tools in Go compiler/runtime/libraries. </li></ul><ul><li>And then attach almighty ThreadSanitizer technology to it. </li></ul><ul><li>If/when committed to main branch, user just specifies a single compiler flag to enable it. </li></ul>
  26. 26. Scalability <ul><li>The goal of Go is to support scalable fine-grained concurrency. But it is [was] not yet there. </li></ul><ul><li>Submitted about 50 scalability-related CLs. Rewrote all sync primitives (mutex, semaphore, once, etc), improve scalability of chan/select, memory allocation, stack mgmt, etc. </li></ul><ul><li>&quot;I've just run a real world benchmark provided by someone using mgo with the r59 release, and it took about 5 seconds out of 20, without any changes in the code.&quot; </li></ul><ul><li>Still to improve goroutine scheduler. </li></ul>
  27. 27.   <ul><li>Thanks! </li></ul>

×