Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

いまさら聞けないselectあれこれ

16.325 visualizaciones

Publicado el

Goにおける重要な構文、selectについて。今更聞けない基本からちょっとしたトリックまで。

Publicado en: Tecnología
  • Sé el primero en comentar

いまさら聞けないselectあれこれ

  1. 1. いまさら聞けない select あれこれ Go Allstars 2 (Oct 2, 2016) 牧大輔 / Daisuke Maki (lestrrat) HDE株式会社
  2. 2. • 牧大輔 (lestrrat) • 株式会社 HDE • Perl/Go/C 等 • builderscon 12月3日 開催!
 https://builderscon.io/
  3. 3. builderscon • 12月3日開催! • Web系エンジニア達に楽しんでもらいつつ、これまでの枠にとらわれない 様々な分野の技術者達が終結! • 是非「知らなかった、を知る」ためにご来場ください。 • トーク募集中!
 https://builderscon.io/builderscon/tokyo/2016/cfp
  4. 4. =
  5. 5. Web+DB Press 10/22
  6. 6. channel++ • 端的に言ってチャンネルは最高 • 排他処理を意識しないデータの移動 • でもチャンネル単体ではできない操作が 結構ある。
  7. 7. func WriteCh(ch chan int) { ch <- 1 // Could block, bah } channels block • バッファ付きチャンネルでもブロックする可能性
  8. 8. func ReadCh(ch chan int) { <-ch // Could block, bah } channels block • 読み込みでも書き込みがあるまでブロック • 戻り値二つの<-chはチャンネルが閉じてあるかどうか の確認にしか使えないので、やっぱりブロックする
  9. 9. つまり • 複数のチャンネルを同時に同じgoroutineで 扱いたい場合はどうする?
  10. 10. go func() { <-ch1 … }() go func() { <-ch2 … }() チョットチガウ…
  11. 11. select • Cのselect使った事ある人: アレです • 複数のchannelの読み書きを制御してくれる • Go中級者なら確実にマスターしてるべき
  12. 12. select { case チャンネル操作: … case チャンネル操作: … default:
 … } 基本形
  13. 13. func CanWeRead(ch <-chan int) { select { case <-ch: … // yes, we can read } } 読み込み
  14. 14. func CanWeRead(ch <-chan int) { select { case <-ch: … // yes, we can read } } 読み込み ポイント:defaultがないとブ ロックするよ!
  15. 15. func CanWeRead(ch <-chan int) { select { case <-ch: … // yes, we can read default: … // no, we could not read } } 読み込み
  16. 16. func CanWeRead(ch <-chan int) { select { case <-ch: … // yes, we can read default: … // no, we could not read } } 読み込み ポイント:読み込みが即時でき ない場合はデフォルトが実行さ れるので、実質的なノンブロッ キングI/O
  17. 17. func CanWeRead(ch <-chan int) { select { case v, ok := <-ch: if !ok { // channel is closed … } fmt.Println(v) } } 値を使う
  18. 18. func CanWeRead(ch <-chan int) { select { case v, ok := <-ch: if !ok { // channel is closed … } fmt.Println(v) } } 値を使う ポイント:代入もできるよ!
  19. 19. func CanWeWrite(ch chan int) { select { case ch<-1: … // yes, we can write default: … // no, we could not write } } 書き込み
  20. 20. func CanWeWrite(ch chan int) { select { case ch<-1: … // yes, we can write default: … // no, we could not write } } 書き込み ポイント:書き込みが即時でき ない場合はデフォルトが実行さ れるので、実質的なノンブロッ キングI/O
  21. 21. ところで • nilなチャンネルに対する書き込み・読み込み の操作ってどうなるか知ってますか?
  22. 22. var ch chan int <-ch // 初期化してないのでch = nil • panic? • ブロック? • その他?
  23. 23. nil channel • 読み込み=ブロック • 書き込み=ブロック
  24. 24. var ch chan int select { case <-ch: … } …ということは
  25. 25. var ch chan int select { case <-ch: … } …ということは ポイント:この読み込みが成功するこ とはない!
  26. 26. select { case <-ch1: … case <-ch2: ch1 = nil // Disable previous case } 特定のケースを無効にする
  27. 27. select { case <-ch1: … case <-ch2: ch1 = nil // Disable previous case } 特定のケースを無効にする ポイント:最初は普通にch1から読み 込み可能
  28. 28. select { case <-ch1: … case <-ch2: ch1 = nil // Disable previous case } 特定のケースを無効にする ポイント:ch2から読み込みができた らch1を無効にしてる。これ以降ch1の caseは実行されることがない
  29. 29. ch1 = nil select { case <-ch1: … case <-ch2: ch1 = … // Enable previous case } 逆バージョン
  30. 30. ch1 = nil select { case <-ch1: … case <-ch2: ch1 = … // Enable previous case } 逆バージョン ポイント:最初はch1 = nilなので絶 対にこのcaseは実行されない。有効な チャンネルを代入すれば動く。
  31. 31. ch1 = nil select { case <-ch1: … case <-ch2: ch1 = … // Enable previous case } 逆バージョン ポイント:ch1 に有効なチャンネルを 代入すればch1のcaseも有効になる
  32. 32. パターン • selectを使ったよくつかうパターン集
  33. 33. t := time.NewTimer(30*time.Second) defer t.Stop() select { case <-t.C: return errors.New(“timeout”) case ch <- 1:
 return nil } 書き込みタイムアウト
  34. 34. t := time.NewTimer(30*time.Second) defer t.Stop() select { case <-t.C: return errors.New(“timeout”) case ch <- 1:
 return nil } 書き込みタイムアウト ポイント: 書き込みが成功したらエ ラー無しで脱出
  35. 35. t := time.NewTimer(30*time.Second) defer t.Stop() select { case <-t.C: return errors.New(“timeout”) case ch <- 1:
 return nil } 書き込みタイムアウト ポイント: 書き込むより先にタイム アウトになったらエラーを返す
  36. 36. t := time.NewTimer(30*time.Second) defer t.Stop() for { select { case <-t.C: // 30秒後にここにくる return default:
 // タイムアウトするまで行う操作 } } タイムアウトまでループ
  37. 37. t := time.NewTimer(30*time.Second) defer t.Stop() for { select { case <-t.C: // 30秒後にここにくる return default:
 // タイムアウトするまで行う操作 } } タイムアウトまでループ ポイント:for で囲まないと一回 defaultの操作をしたら終わっちゃう ので、無限ループにする
  38. 38. t := time.NewTimer(30*time.Second) defer t.Stop() for { select { case <-t.C: // 30秒後にここにくる return default:
 // タイムアウトするまで行う操作 } } タイムアウトまでループ ポイント: タイマーからお知らせが 来たらこのループから脱出
  39. 39. t := time.NewTicker(time.Second) defer t.Stop() for { select { case <-t.C: // 1秒ごとにここにくる // 定期的な処理内容 } } 定期的に実行
  40. 40. t := time.NewTicker(time.Second) defer t.Stop() for { select { case <-t.C: // 1秒ごとにここにくる // 定期的な処理内容 } } 定期的に実行 ポイント:TimerではなくTicker
  41. 41. ところで • closeされたチャンネルから読み込むとどうなる?
  42. 42. time.AfterFunc(5*time.Second, func() { close(done) }) for { select { case <-done:
 return default: // 定期的な処理内容 } } “done”チャンネル
  43. 43. time.AfterFunc(5*time.Second, func() { close(done) }) for { select { case <-done:
 return default: // 定期的な処理内容 } } “done”チャンネル ポイント: チャンネルをcloseすると 読み込みブロックが解除される
  44. 44. time.AfterFunc(5*time.Second, func() { close(done) }) for { select { case <-done:
 return default: // 定期的な処理内容 } } “done”チャンネル ポイント:戻り値は無効だが、ブロッ クは解けるのでループを脱出できる
  45. 45. for { select { case <-ctx.Done():
 return default: // 定期的な処理内容 } } Go 1.7からはContext
  46. 46. Context • context.Contextができてからselectを使う事 がより多くなった
  47. 47. Context • I/Oとか関係なくても、「途中で処理を止め る」系のコードでものすごく良く使う
  48. 48. 例:「リストを処理」 for _, data := range list { select { case <-ctx.Done():
 return default: process(data) } }
  49. 49. 例:「リストを処理」 for _, data := range list { select { case <-ctx.Done():
 return default: process(data) } } ポイント:リスト要素を処理する毎に Doneをチェックし、必要であれば終了
  50. 50. 外道 • いよいよselectの変態的な使いかたを必要とする時
  51. 51. reflect.Select • 動的にselect文を構築 • プログラム実行中にcaseの数や内容を変更できる reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Chan: ch1}, reflect.SelectCase{Chan: ch2}, reflect.SelectCase{Chan: ch3}, })
  52. 52. Web+DB Press 10/22
  53. 53. =
  54. 54. まとめ • チャンネルとselectの複合技で表現の幅が 広がる • 初級→中級になるには押さえておきたい。
  55. 55. builderscon • 12月3日開催! • トーク募集中!
 https://builderscon.io/builderscon/tokyo/2016/cfp
  56. 56. Questions?

×