$30 off During Our Annual Pro Sale. View Details »

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. GoݴޠʹΑΔ
    ฒߦॲཧ
    4.4 orνϟωϧͷਤ
    @pirosikick

    View Slide

  2. • var or(channels ...<-chan interface{}) <-chan interface{}


    • "1つ以上のdoneチャネルを1つのdoneチャネルにまとめて、

    まとめているチャネルのうちのどれか1つのチャネルが閉じられたら、

    まとめたちゃねるも閉じられるようにしたい"


    • <-or(

    done1,

    done2,

    done3,

    )


    • 再帰処理で実装されており、

    コードを読んでいると混乱してしまったので、図にしてみました。

    View Slide

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

    View Slide

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

    View Slide

  5. orDone
    switch {


    case <-channel[0]:


    case <-channel[1]:


    }
    ゴルーチン
    deferでclose
    返り値 =
    <-chan interface{}

    View Slide

  6. orDone
    switch {


    case <-channel[0]:


    case <-channel[1]:


    }
    ゴルーチン
    deferでclose
    返り値 =
    <-chan interface{}
    channel[0] or channel[1]の


    ブロックが解除されたら


    ゴルーチンが終了する。


    その時のdeferでorDoneがcloseされる。

    View Slide

  7. len(channels) == 3 の場合

    View Slide

  8. orDone
    switch {


    case <-channel[0]:


    case <-channel[1]:


    case <-channel[2]:


    case <-orDone:


    }
    ゴルーチン
    deferでclose
    返り値 =
    <-chan interface{}
    チャネルの数が変わっただけで、


    len(channels) == 2 の時とほぼ同じ

    View Slide

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

    View Slide

  10. len(channels) == 4 の場合

    View Slide

  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

    View Slide

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

    View Slide

  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ゴルーチンずつ増えていく

    View Slide

  14. len(channels) == 4 の場合


    で動作をみる

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  21. パターン2


    channel[0]~channel[2]のどれかがclose

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  26. ͓ΘΓ

    View Slide