GopherCon 2018: Bryan C. Mills - Rethinking Classical Concurrency Patterns

Several ideas stand out:

  • implement synchronous APIs
  • caller adds concurrency if needed
  • start goroutines only when you have concurrent work
  • communicate the things you want to share, not just messages about them

Notes:

  • two principals
    • Start goroutines when you have concurrent work
    • share by communicating
  • Asynchronous APIs
    • An asynchronous API returns to the caller before its result is ready.
    • not necessarily concurrent
    • don’t use async callbacks
    • Future
      • async/await
      • Go analog, function that returns channel
    • Producer/consumer queue – similar to future, but receives any number of results and is typically unbuffered
      • for item := range Glob(“[ab*”) …
    • classical benefit – help keep single threaded apps responsive
    • threads are sometimes expensive
    • asynchronicity as an optimization is subtle
    • examples of problems with asynchronous APIs
  • A goroutine is a function executing concurrently with other goroutines in the same address space.
  • Add concurrency on the caller side of the API.
  • example with errgroup.WithContext
  • Make concurrency an internal detail.
    • you can easily see the sending and receiving sides of a channel
  • Concurrency is not Asynchronicity
  • Condition Variables
    • Monitors
    • dates to 1974
    • wait and signal
    • broadcast
    • entire point is to put something to sleep while we wait for something to happen
    • problems
      • spurious wakeups
      • forgotten signals, decouples signal from data
      • starvation
      • unresponsive cancellation
      • communicate by shared memory
  • Go approach is to share by communicating
    • resource pool
      • communicate the resource and the limits
      • buffered channel can be used like a semaphore
    • indicate new data
    • mark transitions
    • communicate the things we want to share, not just messages about them
  • worker pool
    • overhead of threads does not apply in Go, as the runtime manages that
    • benefit in Go: Limit work in flight
  • it’s easy to start goroutines when you need them