LoginSignup
3
0

More than 5 years have passed since last update.

Go context.Context interfaceに Cancelが含まれていない理由

Posted at

参考

Context API explained
https://siadat.github.io/post/context

Cancellation, Context, and Plumbing by Sameer Ajmani
https://vimeo.com/115309491

context packageのメンバー

   var Canceled = errors.New("context canceld")
   var DeadlineExceeded error = deadlineExceededError()

   type CancelFunc func()

   func Background() Context
   func TODO() Context
   func WithCancel(parent Context) (Context, CancelFunc)
   func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
   func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
   func WithValue(parent Context, key val interface{}) Context

   type Context interface {
       // Done returns a channel that is closed when this Context is canceled
       // or times out.
       Done() <-chan struct{}

       // Err indicates why this context was canceled, after the Done channel
       // is closed.
       Err() error

       // Deadline returns the time when this Context will be canceled, if any.
       Deadline() (deadline time.Time, ok bool)

       // Value returns the value associated with key or nil if none.
       Value(key interface{}) interface{}
   }

context packageの背景にある考え

Cancelation should be advisory

 cancelを実行した側は、実行中の処理をstopしたりするべきでなく、もはやその仕事が必要ないという情報を通知するにとどめる。
 cancelを通知された側がshot down, clean up, return errors等、なにをするかを決定する。

golang 3ways to iterate にあった、channelを利用したiterate処理でも、cancelを呼んだ後にも channelをdrainしなければいけなかったのも、cancelがなにかの処理を強制するのではなくあくまで、advisoryだからと考えると自然だなと思えました。

Context are hierarchical

 cancelという指示は常にparent(caller) から child(callee)にむかって流れなくてはいけない。
もし、 context.ContextCancel() が定義されていると、ctxを渡された側がctx.Cancel() を呼べてしまうので、 WithCancel()等のmethodは明示的にContextとは別に CancelFunc を返している。
ctx を他のgroutineに渡してもその ctx はそれを作成したCode以外からはcancelされず、 cancel可能な ctxが必要な場合は明示的に WithCancel() 等で新しい ctx を作成しなければいけない。
 context packageを既に理解されている方には、なにを当たり前なと思われるかもしれないですが、自分としては今週一番のなるほどでした。

ついでに

Done() がchannelを返す理由

booleanではなくてchannelが返ってくる明確な理由はわかりませんが

closing a channel works well as a broadcast signal

とあり、context packageのcommentにも

Done is provided for use in select statement

とあるので、selectの中で利用することを意図しているからというのが現状の理解です。
また、 nil channelやcloseされたchannelをcloseするとpanicが起きてしまいますが、Done() が返すchannelは WithCancel()等で返された CancelFuncによってのみ一度だけcloseされるようになっているようです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0