Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go言語による並行処理「4.4 orチャネル」の図

Go言語による並行処理「4.4 orチャネル」の図

コードを読んでいて混乱したので図にしました。

Dc52871050369929247b69f3767e8737?s=128

Hiroyuki ANAI

October 05, 2021
Tweet

More Decks by Hiroyuki ANAI

Other Decks in Technology

Transcript

  1. GoݴޠʹΑΔ ฒߦॲཧ 4.4 orνϟωϧͷਤ @pirosikick

  2. • var or(channels ...<-chan interface{}) <-chan interface{} • "1つ以上のdoneチャネルを1つのdoneチャネルにまとめて、 


    まとめているチャネルのうちのどれか1つのチャネルが閉じられたら、 
 まとめたちゃねるも閉じられるようにしたい" • <-or( 
 done1, 
 done2, 
 done3, 
 ) • 再帰処理で実装されており、 
 コードを読んでいると混乱してしまったので、図にしてみました。
  3. len(channels) == 0 の場合 返り値は nil 返り値は channels[0] len(channels) ==

    1 の場合
  4. len(channels) == 2 の場合

  5. orDone switch { case <-channel[0]: case <-channel[1]: } ゴルーチン deferでclose

    返り値 = <-chan interface{}
  6. orDone switch { case <-channel[0]: case <-channel[1]: } ゴルーチン deferでclose

    返り値 = <-chan interface{} channel[0] or channel[1]の ブロックが解除されたら ゴルーチンが終了する。 その時のdeferでorDoneがcloseされる。
  7. len(channels) == 3 の場合

  8. orDone switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone: } ゴルーチン deferでclose 返り値 = <-chan interface{} チャネルの数が変わっただけで、 len(channels) == 2 の時とほぼ同じ
  9. orDone switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone: } ゴルーチン deferでclose 返り値 = <-chan interface{} 最後のcaseは再帰呼び出しの返り値。 case <-or(append(channels[3:], orDone)): len(channels) == 3の場合、 orDoneが再帰呼び出しの返り値になる。
  10. len(channels) == 4 の場合

  11. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close
  12. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close ↑再帰呼び出しでできたやつ 
 orDone2 := or(append(channels[3:], orDone1))
  13. orDone1 switch { … } ゴルーチン1 deferで close 返り値 =

    <-chan interface{} switch { … } ゴルーチン2 orDone2 deferで close <-chan interface{} switch { … } ゴルーチン3 orDone3 deferで close <-chan interface{} ・ ・ ・ channelが3つにつき、 1ゴルーチンずつ増えていく
  14. len(channels) == 4 の場合 で動作をみる

  15. パターン1 channel[3]がclose

  16. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン1 channel[3]がcloseされた場合 switchを抜け、 ゴルーチン2が終了する
  17. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ ゴルーチン終了時の deferでorDone2をclose
  18. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ orDone2をcloseしたので、 switchを抜け、 ゴルーチン1が終了。 closed
  19. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ closed switchΛൈ͚ͯ ऴྃ deferで close ゴルーチン終了時の deferでorDone1をclose
  20. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ closed switchΛൈ͚ͯ ऴྃ deferで close closed ✅ Done
  21. パターン2 channel[0]~channel[2]のどれかがclose

  22. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close パターン2 channel[0] ~ channel[2] のどれかがcloseされた場合 switchを抜け、 ゴルーチン1が終了する
  23. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close switchΛൈ͚ͯ ऴྃ deferで close ゴルーチン終了時の deferでorDone1をclose パターン2 channel[0] ~ channel[2] のどれかがcloseされた場合
  24. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close switchΛൈ͚ͯ ऴྃ 再帰呼び出し時に渡した orDone1がcloseしたので、 switchを抜け、 ゴルーチン2も終了する closed パターン2 channel[0] ~ channel[2] のどれかがcloseされた場合 ※再帰呼び出し時に呼び出し側のorDone(例のorDone1)を渡すのは、 子ゴルーチン(例のゴルーチン2)をcloseするため
  25. orDone1 switch { case <-channel[0]: case <-channel[1]: case <-channel[2]: case

    <-orDone2: } ゴルーチン1 返り値 = <-chan interface{} switch { case <-channel[3]: case <-orDone1: } ゴルーチン2 orDone2 deferで close switchΛൈ͚ͯ ऴྃ switchΛൈ͚ͯ ऴྃ closed deferで close ✅ Done パターン2 channel[0] ~ channel[2] のどれかがcloseされた場合
  26. ͓ΘΓ