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

【Crystal】Concurrency

 【Crystal】Concurrency

crystal.tokyo #7 での発表資料です。
https://crystal.connpass.com/event/93629/

at_grandpa

July 18, 2018
Tweet

More Decks by at_grandpa

Other Decks in Technology

Transcript

  1. Concurrency
    2018.07.18 @at_grandpa
    Crystal.tokyo #7 in 渋谷

    View Slide

  2. @at_grandpa

    View Slide

  3. 圧倒亭グランパのブログ

    View Slide

  4. Concurrency

    View Slide

  5. ✔ Concurrency の雰囲気を話します
    ✔ 細かい syntax などはドキュメント参照

    View Slide

  6. View Slide

  7. “as in Go or Clojure”
    ✔ Go の goroutine/channel とほぼ同じ
    終了!

    View Slide

  8. Concurrency の中身を
    ちょっと覗いてみましょう

    View Slide

  9. サンプルコード
    ✔ 並行処理
    ✔ 各処理からの値の取得

    View Slide

  10. View Slide

  11. String型のChannelをインスタンス化

    View Slide

  12. 2つのFiberを生成

    View Slide

  13. Channel経由で値を取得

    View Slide

  14. 2018-07-18 08:12:50 +09:00 start
    2018-07-18 08:12:50 +09:00 [fiber 1] start
    2018-07-18 08:12:50 +09:00 [fiber 2] start
    2018-07-18 08:12:55 +09:00 [top level] value: send from fiber 1
    2018-07-18 08:12:55 +09:00 [fiber 1] end
    2018-07-18 08:13:00 +09:00 [top level] value: send from fiber 2
    2018-07-18 08:13:00 +09:00 end

    View Slide

  15. 2018-07-18 08:12:50 +09:00 start
    2018-07-18 08:12:50 +09:00 [fiber 1] start
    2018-07-18 08:12:50 +09:00 [fiber 2] start
    2018-07-18 08:12:55 +09:00 [top level] value: send from fiber 1
    2018-07-18 08:12:55 +09:00 [fiber 1] end
    2018-07-18 08:13:00 +09:00 [top level] value: send from fiber 2
    2018-07-18 08:13:00 +09:00 end
    ・並行に動いている
    ・値も取れている

    View Slide

  16. どういう仕組みで動いているか

    View Slide

  17. ✔ Fiber

    ✔ Runtime Scheduler

    ✔ Event Loop
    ✔ Channel

    ✔ IO::Syscall
    Concurrencyを理解するポイント

    View Slide

  18. Fiber
    ✔ Process ⊃ Thread ⊃ Fiber

    ✔ 協調マルチタスク

     - Fiber自ら、処理を他のFiberに委譲する
     - 1つのFiberが固まるとシステム全体が固まる

    ✔ Crystalの処理は全てFiberで行われている

     - 「Main Fiber」でメインの処理を実行している

    View Slide

  19. Runtime Scheduler
    ✔ Fiberの切り替えを担当

    ✔ クラス変数にFiberのqueueを持っている

     - @@runnables = Deque(Fiber).new

     - 実行可能Fiberのqueue
    ✔ Scheduler.rescheduleで切り替え

    View Slide

  20. Event Loop
    ✔ I/O処理の委譲先

    ✔ 委譲している間に別のFiberを実行できる
    ✔ I/O処理が終了したら委譲元のFiberに移る

    View Slide

  21. Channel
    ✔ Fiber間のデータのやりとり

    ✔ 送信元Fiberや受信先Fiberを保持
     - @senders = Deque(Fiber).new

     - @receivers = Deque(Fiber).new
    ✔ 送受信時にFiberを切り替え

     - Runtime Scheduler を使う

    View Slide

  22. IO::Syscall
    ✔ 以下でincludeされている

     - Crystal::System::FileDescriptor

     - Socket

    ✔ read/writeでFiber切り替え
     - Runtime Scheduler を使う
    ほぼ全てのI/Oを網羅

    View Slide

  23. 実際の動き追う

    View Slide

  24. View Slide

  25. Channelをインスタンス化

    View Slide

  26. ・Fiber1を定義
    ・Runtime Scheduler の
     実行可能Fiberのqueueに
     Fiber1が enqueue される

    View Slide

  27. concurrency.cr
    ・Fiber1を定義
    ・Runtime Scheduler の
     実行可能Fiberのqueueに
     Fiber1が enqueue される

    View Slide

  28. ・Fiber2を定義
    ・Runtime Scheduler の
     実行可能Fiberのqueueに
     Fiber2が enqueue される

    View Slide

  29. ・実際の処理はここから開始
    ・Top Level のコードは
     「Main Fiber」で動いている
    ・Channelの送受信時には
     Fiberの切り替えが行われる

    View Slide

  30. ・実際の処理はここから開始
    ・Top Level のコードは
     「Main Fiber」で動いている
    ・Channelの送受信時には
     Fiberの切り替えが行われる
    ・Runtime Scheduler の
     実行可能Fiberのqueue
     からshift
    ・Fiber1に処理が移る

    View Slide

  31. ・Fiber1に処理が移った

    View Slide

  32. ・sleep

    View Slide

  33. concurrency.cr

    View Slide

  34. concurrency.cr
    fiber.cr

    View Slide

  35. concurrency.cr
    fiber.cr
    ・Event Loop に処理を委譲
    ・Runtime Scheduler で
     queueの次のFiber切り替え

    View Slide

  36. concurrency.cr
    fiber.cr
    ・Event Loop に処理を委譲
    ・Runtime Scheduler で
     queueの次のFiber切り替え
    ・Fiber2へ移る

    View Slide

  37. ・Fiber2に処理が移った

    View Slide

  38. ・同じくFiber切り替え
    ・しかし、もう
     実行可能Fiberのqueueには
     Fiberが存在しない
    ・I/O処理を待機するしかない

    View Slide

  39. 待機中 . . .

    View Slide

  40. ・Event Loop が sleep 5 の
     終了を検知
    ・処理中のFiberが他にいないので
     Fiber1の処理が再開される

    View Slide

  41. ・Channelに値を送信
    ・sendの場合はreceiveを
     呼んだFiberに切り替え
    ・Main Fiber に切り替わる
    ・このとき、sendしたFiberを
     Schedulerのqueueにenqueue

    View Slide

  42. ・Channelに値を送信
    ・sendの場合はreceiveを
     呼んだFiberに切り替え
    ・Main Fiber に切り替わる
    ・このとき、sendしたFiberを
     Schedulerのqueueにenqueue

    View Slide

  43. ・受信された値を表示

    View Slide

  44. ・Schedulerの
     実行可能Fiberのqueueを元に
     Fiberの切り替え
    ・queueにはsendした際に
     enqueueされたFiber1が入っている

    View Slide

  45. ・Schedulerの
     実行可能Fiberのqueueを元に
     Fiberの切り替え
    ・queueにはsendした際に
     enqueueされたFiber1が入っている
    ・Fiber1が再開

    View Slide

  46. ・値の表示

    View Slide

  47. ・Fiber1のブロックが終了
    ・Fiberの切り替えが発生
    ・しかし、Schedulerの
     queueには実行可能Fiberが
     存在しない

    View Slide

  48. 待機中 . . .

    View Slide

  49. ・Event Loop が sleep 10 の
     終了を検知
    ・処理中のFiberが他にいないので
     Fiber2に処理が戻る

    View Slide

  50. ・Channelに値を送信
    ・sendの場合はreceiveを
     呼んだFiberに切り替え
    ・Main Fiber に切り替わる
    ・このとき、sendしたFiberを
     Schedulerのqueueにenqueue

    View Slide

  51. ・Channelに値を送信
    ・sendの場合はreceiveを
     呼んだFiberに切り替え
    ・Main Fiber に切り替わる
    ・このとき、sendしたFiberを
     Schedulerのqueueにenqueue

    View Slide

  52. ・受信された値を表示

    View Slide

  53. ・そのまま終了

    View Slide

  54. ・そのまま終了
    ・ここは通らない

    View Slide

  55. ・そのまま終了
    ・ここは通らない
    2018-07-18 08:12:50 +09:00 start
    2018-07-18 08:12:50 +09:00 [fiber 1] start
    2018-07-18 08:12:50 +09:00 [fiber 2] start
    2018-07-18 08:12:55 +09:00 [top level] value: send from fiber 1
    2018-07-18 08:12:55 +09:00 [fiber 1] end
    2018-07-18 08:13:00 +09:00 [top level] value: send from fiber 2
    2018-07-18 08:13:00 +09:00 end [fiber 2] end は表示されてない

    View Slide

  56. 複雑!

    View Slide

  57. とはいえ
    ✔ Concurrencyに必要な役者を知る

     - Fiber, Runtime Scheduler, Event loop, Channel

    ✔ Fiberが切り替わるタイミングを知る

     - I/Oの場合

      - 実行可能Fiber-queueからshift

     - receiveの場合

      - 実行可能Fiber-queueからshift

      - sendしたFiberをqueueにenqueue

     - sendの場合

      - receiveしたFiberに切り替え
    これらを知るだけで、だいぶ変わる

    View Slide

  58. まとめ

    View Slide

  59. ✔ 並行処理
    ✔ Concurrencyに必要な役者を知ろう

    ✔ Fiberを切り替えるタイミングを知ろう
    Concurrency

    View Slide

  60. ✔ 立て続けにsendされたらどうなるの?

     - sendされた値もqueueに保存される

     - receiveを呼ぶ度にqueueからshift
    ✔ Fiber内でI/O以外の重い処理があったら?
     - 委譲できない処理はそのまま処理される

     - その処理が終わるまで他のFiberは実行できない

    ✔ 入れ子spawnとかどうなるんだろう?

     - \(^o^)/
    まだまだあるよ

    View Slide

  61. Happy Crystalling !
    fin

    View Slide