Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Coding in the context era

2,592 views

Published on

Introduction to why you should use change how you code now that context.Context is starting to come up in stdlib

Published in: Technology
  • Be the first to comment

Coding in the context era

  1. 1. Coding in the Context Era Go Conference 2017 Spring Mar 25, 2017 Daisuke Maki @lestrrat
  2. 2. • @lestrrat • Perl/Go hacker, author, father • Author of github.com/peco/peco • Organizer for builderscon
  3. 3. uilderscon https://builderscon.io/tokyo/2017 Aug 3, 4, 5 2017
  4. 4. (we run on Kubernetes)
  5. 5. </advertisement>
  6. 6. Web+DB Press vol 98 (Apr 2017)
  7. 7. you DO use context.Context, right?
  8. 8. obj.Start() obj.Stop()
  9. 9. func (t *Obj) Start() { go func() { for { select {
 case <-t.done: … default: } … }() } } }
  10. 10. func (t *Obj) Stop() { close(t.done) }
  11. 11. THIS IS NOT SAFE
  12. 12. obj.Start() obj.Start() // What?!
  13. 13. API is ambiguous • Does it start a new goroutine every time Start() is called? • Does it error from the second one?
  14. 14. Only start one? • Maybe Start() can return an error if it has already been started • Bonus points: can it be re-entrant? • Requires state synchronization
  15. 15. func (obj *Obj) Start() error { obj.mu.Lock() if obj.started { obj.mu.Unlock() return errors.New(`already running`) } obj.started = true obj.mu.Unlock() … }
  16. 16. func (obj *Obj) Start() error { … go func() { defer func() { obj.mu.Lock() obj.started = false obj.mu.Unlock() }() for { … } }() }
  17. 17. func (obj *Obj) Start() error { … go func() { for { select { case <-obj.done: return default:
 } } … }() }
  18. 18. func (obj *Obj) Stop() error { obj.mu.Lock() if obj.started { close(obj.done) obj.mu.Unlock() return errors.New(`already running`) } obj.started = true obj.Unlock() }
  19. 19. This is still a simplified version.
  20. 20. Life is too short for manual synchronization of concurrently executed code 人類に並行実行されている コードの手動同期は難しすぎる…!
  21. 21. Nobody wants to do this
  22. 22. Root cause: shared resource • obj.started is shared • There is no way to escape manual locking
  23. 23. TRUTH YOU WILL MAKE A MISTAKE WHEN MANUALLY SYNCHRONIZING sync.Mutexes
  24. 24. AVOID sync.Mutex (unless you know what you are doing)
  25. 25. context.Contextcontext.Context
  26. 26. context.Context • abstracts away shared state for cancellation
  27. 27. context.Context • Explicit cancellation • Timeouts • Deadlines • It’s a pattern: you can use it anywhere!
  28. 28. // To save some typing, please assume the // following for the rest of this talk: ctxbg := context.Background() delay := 5 * time.Second
  29. 29. func (obj *Obj) Run(ctx context.Context) error { for { select { case <-ctx.Done(): return nil default: } … } }
  30. 30. ctx, cancel := context.WithCancel(ctxbg) go obj.Run(ctx) // later in your code cancel()
  31. 31. No sync.Mutex!
  32. 32. Clean, explicit grouting termination
  33. 33. No ambiguous API
  34. 34. ctx, cancel := context.WithTimeout(ctxbg, delay) defer cancel() go obj1.Run(ctx) // use a diff. ctx if need be go obj2.Run(ctx) // re-entrant! yay! go obj3.Run(ctx) Explicit semantics
  35. 35. YESSS!!!!
  36. 36. Prediction/Recommendation • Almost everything that can (1) block or (2) spawn a goroutine will support context.Context very soon. • You should use context.Context for anything that blocks!
  37. 37. Learn to ♡ contexts
  38. 38. Questions?

×