Date post: | 11-Apr-2017 |
Category: |
Technology |
Upload: | lestrrat |
View: | 1,477 times |
Download: | 0 times |
• @lestrrat • Perl/Go hacker, author, father • Author of github.com/peco/peco • Organizer for builderscon
API is ambiguous• Does it start a new goroutine every time Start() is called?
• Does it error from the second one?
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
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() … }
func (obj *Obj) Start() error { … go func() { defer func() { obj.mu.Lock() obj.started = false obj.mu.Unlock() }() for { … } }() }
func (obj *Obj) Start() error { … go func() { for { select { case <-obj.done: return default: } } … }() }
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() }
Life is too short for manual synchronization of concurrently executed code
人類に並行実行されている コードの手動同期は難しすぎる…!
context.Context• Explicit cancellation • Timeouts • Deadlines • It’s a pattern: you can use it anywhere!
// To save some typing, please assume the // following for the rest of this talk: ctxbg := context.Background() delay := 5 * time.Second
func (obj *Obj) Run(ctx context.Context) error { for { select { case <-ctx.Done(): return nil default: } … } }
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
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!