コードを読んでいて混乱したので図にしました。
GoݴޠʹΑΔฒߦॲཧ4.4 orνϟωϧͷਤ@pirosikick
View Slide
• var or(channels ...<-chan interface{}) <-chan interface{}• "1つ以上のdoneチャネルを1つのdoneチャネルにまとめて、 まとめているチャネルのうちのどれか1つのチャネルが閉じられたら、 まとめたちゃねるも閉じられるようにしたい"• <-or( done1, done2, done3, )• 再帰処理で実装されており、 コードを読んでいると混乱してしまったので、図にしてみました。
len(channels) == 0 の場合返り値は nil返り値は channels[0]len(channels) == 1 の場合
len(channels) == 2 の場合
orDoneswitch {case <-channel[0]:case <-channel[1]:}ゴルーチンdeferでclose返り値 =<-chan interface{}
orDoneswitch {case <-channel[0]:case <-channel[1]:}ゴルーチンdeferでclose返り値 =<-chan interface{}channel[0] or channel[1]のブロックが解除されたらゴルーチンが終了する。その時のdeferでorDoneがcloseされる。
len(channels) == 3 の場合
orDoneswitch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone:}ゴルーチンdeferでclose返り値 =<-chan interface{}チャネルの数が変わっただけで、len(channels) == 2 の時とほぼ同じ
orDoneswitch {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が再帰呼び出しの返り値になる。
len(channels) == 4 の場合
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでclose
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでclose↑再帰呼び出しでできたやつ orDone2 := or(append(channels[3:], orDone1))
orDone1 switch { … }ゴルーチン1deferでclose返り値 =<-chan interface{}switch { … }ゴルーチン2orDone2deferでclose<-chan interface{}switch { … }ゴルーチン3orDone3deferでclose<-chan interface{}・・・channelが3つにつき、1ゴルーチンずつ増えていく
len(channels) == 4 の場合で動作をみる
パターン1 channel[3]がclose
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン1 channel[3]がcloseされた場合switchを抜け、ゴルーチン2が終了する
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン1 channel[3]がcloseされた場合switchΛൈ͚ͯऴྃゴルーチン終了時のdeferでorDone2をclose
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン1 channel[3]がcloseされた場合switchΛൈ͚ͯऴྃorDone2をcloseしたので、switchを抜け、ゴルーチン1が終了。closed
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン1 channel[3]がcloseされた場合switchΛൈ͚ͯऴྃclosedswitchΛൈ͚ͯऴྃdeferでcloseゴルーチン終了時のdeferでorDone1をclose
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン1 channel[3]がcloseされた場合switchΛൈ͚ͯऴྃclosedswitchΛൈ͚ͯऴྃdeferでcloseclosed✅ Done
パターン2channel[0]~channel[2]のどれかがclose
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseパターン2 channel[0] ~ channel[2] のどれかがcloseされた場合switchを抜け、ゴルーチン1が終了する
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseswitchΛൈ͚ͯऴྃdeferでcloseゴルーチン終了時のdeferでorDone1をcloseパターン2 channel[0] ~ channel[2] のどれかがcloseされた場合
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1deferでclose返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseswitchΛൈ͚ͯऴྃ再帰呼び出し時に渡したorDone1がcloseしたので、switchを抜け、ゴルーチン2も終了するclosedパターン2 channel[0] ~ channel[2] のどれかがcloseされた場合※再帰呼び出し時に呼び出し側のorDone(例のorDone1)を渡すのは、子ゴルーチン(例のゴルーチン2)をcloseするため
orDone1switch {case <-channel[0]:case <-channel[1]:case <-channel[2]:case <-orDone2:}ゴルーチン1返り値 =<-chan interface{}switch {case <-channel[3]:case <-orDone1:}ゴルーチン2orDone2deferでcloseswitchΛൈ͚ͯऴྃswitchΛൈ͚ͯऴྃcloseddeferでclose✅ Doneパターン2 channel[0] ~ channel[2] のどれかがcloseされた場合
͓ΘΓ