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

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

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

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

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

Avatar for Hiroyuki ANAI

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された場合