post Image
contextの使い方

https://tip.golang.org/doc/go1.7#context

Go1.7で golang.org/x/net/context が
標準ライブラリに入るようなので改めて使い方のメモ。

変数の管理

ctx := context.Background()
ctx = context.WithValue(ctx, "Foo", 1)
ctx = context.WithValue(ctx, "Bar", 2)

fmt.Println(ctx.Value("Foo").(int)) // 1

よくあるやつ。値を代入するたびに新しいcontextが生成される。
なので、乱暴に値を上書かない限りはあまり状態を気にしなくていい。

TimeoutとCancel

func WithCancel func WithDeadline func WithTimeout はキャンセルを取り扱う。

WithTimeout, WithDeadline は特定時間になったタイミングでキャンセルされる。
引数で指定の仕方が 何秒後かと時刻指定がなのが違うだけ。

実際にWithTimeoutの中身は WithDeadlineを呼んでいるだけ。

WithTimeout, WithDeadline

指定した時間後にキャンセルイベントが起きる。

// 5秒かかる処理
func heavyFunc(ctx context.Context) {
  time.Sleep(5 * time.Second)
}

func main() {
  ctx := context.Background()
  ctx, cancel := context.WithTimeout(ctx, time.Second) // 1秒後にキャンセル
  defer cancel()

  go heavyFunc(ctx)
  go heavyFunc(ctx)

  select {
  case <-ctx.Done(): // 1秒以上かかると Done() がcloseされる
    fmt.Println("done:", ctx.Err()) // done: context deadline exceeded
  }
}

WithCancel

自分でキャンセルを使う場合に使う

func heavyFunc(ctx context.Context) {
  time.Sleep(5 * time.Second)
}

func main() {
  ctx := context.Background()
  ctx, cancel := context.WithCancel(ctx)

  go heavyFunc(ctx)
  go heavyFunc(ctx)

  cancel() // 即キャンセル

  select {
  case <-ctx.Done():
    fmt.Println("done:", ctx.Err()) // done: context canceled
  }
}

キャンセルの伝搬

親がキャンセルされると子にキャンセルが伝搬されていく

func main() {
  ctx := context.Background()

  parent, parentCancel := context.WithCancel(ctx)
  child, childCancel := context.WithCancel(parent)
  defer childCancel()

  go heavyFunc(ctx)

  go func() { // 親を1秒後にキャンセル
    time.Sleep(time.Second)
    parentCancel()
    fmt.Println("parent cancelled")
  }()

  select {
  case <-child.Done(): // 子もキャンセルされる
    fmt.Println("parent:", parent.Err()) // parent: context canceled
    fmt.Println("child:", child.Err()) // child: context canceled
  }
}

使い方

goroutineで処理を実行して、所定より時間がかかった場合にエラーを返すのに使う。
ただ、結果が欲しい場合は、contextとは違う形でchannelを使い、値を受け取って返すようにする。(だいたいこっちの使い方になる)

func heavyFunc(ctx context.Context) error {
  time.Sleep(time.Second)
  return nil
}

func exec(ctx context.Context) error {
  errChan := make(chan error, 1)

  go func() {
    errChan <- heavyFunc(ctx)
  }()

  select {
  case <-ctx.Done(): // キャンセルが発生した場合
    return ctx.Err()
  case err := <-errChan: // heavyFuncの結果を取得した場合
    return err
  }
}

func main() {
  ctx := context.Background()
  ctx, cancel := context.WithTimeout(ctx, 2*time.Second) // 全体2秒でタイムアウト
  defer cancel()

  if err := exec(ctx); err != nil {
    log.Fatal(err)
  } else {
    log.Print("ok")
  }
}

まとめ

contextを使うと、値の取り回しやキャンセル処理は楽になる。だけど、goroutineを大量に使って細かく状態を管理をやってくれるものではないので注意。

参考

x/net/context の実装パターン


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。