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

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

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

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

Hiroyuki ANAI

October 05, 2021
Tweet

More Decks by Hiroyuki ANAI

Other Decks in Technology

Transcript

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


    まとめているチャネルのうちのどれか1つのチャネルが閉じられたら、 
 まとめたちゃねるも閉じられるようにしたい" • <-or( 
 done1, 
 done2, 
 done3, 
 ) • 再帰処理で実装されており、 
 コードを読んでいると混乱してしまったので、図にしてみました。
  2. orDone switch { case <-channel[0]: case <-channel[1]: } ゴルーチン deferでclose

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

    <-orDone: } ゴルーチン deferでclose 返り値 = <-chan interface{} チャネルの数が変わっただけで、 len(channels) == 2 の時とほぼ同じ
  4. 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が再帰呼び出しの返り値になる。
  5. 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
  6. 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))
  7. orDone1 switch { … } ゴルーチン1 deferで close 返り値 =

    <-chan interface{} switch { … } ゴルーチン2 orDone2 deferで close <-chan interface{} switch { … } ゴルーチン3 orDone3 deferで close <-chan interface{} ・ ・ ・ channelが3つにつき、 1ゴルーチンずつ増えていく
  8. 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が終了する
  9. 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
  10. 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
  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 パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ closed switchΛൈ͚ͯ ऴྃ deferで close ゴルーチン終了時の deferでorDone1を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 パターン1 channel[3]がcloseされた場合 switchΛൈ͚ͯ ऴྃ closed switchΛൈ͚ͯ ऴྃ deferで close closed ✅ Done
  13. 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が終了する
  14. 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された場合
  15. 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するため
  16. 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された場合