Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

• var or(channels ...<-chan interface{}) <-chan interface{} • "1つ以上のdoneチャネルを1つのdoneチャネルにまとめて、 
 まとめているチャネルのうちのどれか1つのチャネルが閉じられたら、 
 まとめたちゃねるも閉じられるようにしたい" • <-or( 
 done1, 
 done2, 
 done3, 
 ) • 再帰処理で実装されており、 
 コードを読んでいると混乱してしまったので、図にしてみました。

Slide 3

Slide 3 text

len(channels) == 0 の場合 返り値は nil 返り値は channels[0] len(channels) == 1 の場合

Slide 4

Slide 4 text

len(channels) == 2 の場合

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

len(channels) == 3 の場合

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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が再帰呼び出しの返り値になる。

Slide 10

Slide 10 text

len(channels) == 4 の場合

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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))

Slide 13

Slide 13 text

orDone1 switch { … } ゴルーチン1 deferで close 返り値 = <-chan interface{} switch { … } ゴルーチン2 orDone2 deferで close <-chan interface{} switch { … } ゴルーチン3 orDone3 deferで close <-chan interface{} ・ ・ ・ channelが3つにつき、 1ゴルーチンずつ増えていく

Slide 14

Slide 14 text

len(channels) == 4 の場合 で動作をみる

Slide 15

Slide 15 text

パターン1 channel[3]がclose

Slide 16

Slide 16 text

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が終了する

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

パターン2 channel[0]~channel[2]のどれかがclose

Slide 22

Slide 22 text

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が終了する

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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するため

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

͓ΘΓ