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

同期的なプログラミング言語の視点から非同期処理を理解する/understand async from sync

同期的なプログラミング言語の視点から非同期処理を理解する/understand async from sync

PHPerKaigi 2022 の登壇資料です。
原題は「PHPでEventLoopを書いて非同期処理を完全に理解する」です。

Ryo Tomidokoro

April 10, 2022
Tweet

More Decks by Ryo Tomidokoro

Other Decks in Technology

Transcript

  1. @hanhan1978
    PHPでEventLoopを書いて非同期処理を
    完全に理解する
    PHPerKaigi 2022

    View full-size slide

  2. @hanhan1978
    同期的なプログラミング言語の目線から非
    同期処理を理解する
    PHPerKaigi 2022
    とりあえず改題

    View full-size slide

  3. イベントループは関係なかった
    3
    すまんな!

    View full-size slide

  4. @hanhan1978
    ● 富所 亮
    ● 所属
    株式会社カオナビ Expert
    ● 職業
    Webアプリケーションエンジニア
    ● ブログ
    https://blog.hanhans.net
    ● Yokohama North AM
    https://anchor.fm/yokohama-north-am
    4

    View full-size slide

  5. 前回までのあらすじ
    5

    View full-size slide

  6. 2021-11-25 PHP 8.1 Release
    Fibers が導入される
    6

    View full-size slide

  7. 7
    「非同期処理が簡単にかけるようになるらしいぜ?」

    View full-size slide

  8. ここにビジネスチャンスを見出したが....
    非同期沼に突入
    分かりにくいプレゼンを行ってしまう
    8

    View full-size slide

  9. 9
    https://speakerdeck.com/hanhan1978/php-async-programming

    View full-size slide

  10. 3行でまとめると...
    - 非同期処理はわからん
    - Fibers もよくわからん
    - とりあえず、PHPでPHPを動かせ
    10
    すまんかった

    View full-size slide

  11. 11
    リベンジ
    https://speakerdeck.com/hanhan1978/fiber-and-async-request

    View full-size slide

  12. 3行でまとめると...
    - なぜ Fibers
    - イベントループってなに?
    - なぜ 非同期の仕組みがいまさらPHPに入ってくる?
    12
    自信作だったが、スライドが荒かった

    View full-size slide

  13. 本日は合体整理版
    13

    View full-size slide

  14. ● 非同期処理とは
    ● 2つの視点
    ● イベントループ
    ● まとめ
    目次
    14

    View full-size slide

  15. ● 非同期処理とは
    ● 2つの視点
    ● イベントループ
    ● まとめ
    目次
    15

    View full-size slide

  16. 同期的なプログラミング
    記述したとおりの順番で動作するようなプログラミングモデル
    非同期プログラミング
    独立して発生するイベントに対する処理を記述するための並行プログラミン
    グ手法の総称
    16
    高野祐輝. (2021). 並行プログラミング入門 5章 (初版.). オライリー・ジャパン.

    View full-size slide

  17. 17
    PHPアプリケーションは
    同期的なBlocking IOが基本

    View full-size slide

  18. 18
    よくある MVC フレームワークのコード例

    View full-size slide

  19. 19
    プログラムは書いた順番に順次実行され
    ていく

    View full-size slide

  20. 20
    入出力処理が行われると
    プログラムは結果を待つ

    View full-size slide

  21. 21
    DB検索の処理シーケンス
    クエリ結果が返ってくるまで
    メインの処理は待つ
    ブロッキングIOと言う

    View full-size slide

  22. 22
    非同期プログラミングの例

    View full-size slide

  23. 23
    単純なAPIコールの例

    View full-size slide

  24. 24
    ここで処理が待たない

    View full-size slide

  25. 25
    IO処理の結果を待たない
    メインスレッドは、待ち時間の間
    に他の処理を行える
    ノンブロッキングIO という

    View full-size slide

  26. 26
    実行順序は直感と反する



    慣れれば分かるんだが ......

    View full-size slide

  27. 入出力処理の結果が、いつ返ってくるか分からないの
    で、結果が戻ってきたときに実行する処理をコール
    バックで渡しておく
    27

    View full-size slide

  28. 28
    非同期プログラミングの利点

    View full-size slide

  29. 29
    ブロッキング ノンブロッキング
    CPUを効率的に利用できる

    View full-size slide

  30. マルチスレッドは難しすぎたが
    非同期プログラミングであれば、普通の人間でもギリギリ許
    容できそう。
    Promise, Async/Await などを使えば、非同期処理も扱いや
    すくなる。
    30

    View full-size slide

  31. 世の中の潮流としては、マルチコア
    -> コアの利用効率を上げることで、プログラムの処理効率
    を上げる
    スループットの向上
    31

    View full-size slide

  32. ● 非同期処理とは
    ● 2つの視点
    ● イベントループ
    ● まとめ
    目次
    32

    View full-size slide

  33. 33
    非同期処理を考える時の二つの視点

    View full-size slide

  34. 34
    1リクエスト
    複数リクエスト(プロセス)

    View full-size slide

  35. 35
    1リクエスト単位の視点

    View full-size slide

  36. 37
    ToDoリストを検索するバックエンドの処理(例)
    非同期処理チャンス

    View full-size slide

  37. 38
    ToDoリストを検索するバックエンドの処理(例)
    2つめのクエリが1つ目のクエリに依存して
    いる
    無邪気に非同期処理を書くと、整合性のある
    データを取得できない

    View full-size slide

  38. 39
    コールバックPHPの仮想コード

    View full-size slide

  39. 40
    コールバックPHPの仮想コード
    結果出力時には、検索が終わってなければいけ
    ない。
    非同期処理をしてしまうと、データ取得前に結果
    出力するはめになる

    View full-size slide

  40. しょうがないので、全部コールバックにする....
    こうして、コールバック地獄が生まれる
    41

    View full-size slide

  41. 42
    コールバックPHPの仮想コード

    View full-size slide

  42. 43
    コールバックPHPの仮想コード
    同期的プログラミングのコードのほうがはるかに
    見通しが良い。
    処理時間も変わらない......

    View full-size slide

  43. コールバックは、直列に実行され、データが戻ってくるまで待
    つことになるので、非同期処理の書き方をしたところで、ス
    ループットが上がっていない。
    ※相互に依存した処理の場合、1リクエスト単位で見ると同
    期でも非同期でも処理時間は変わらない
    44

    View full-size slide

  44. Fibers が いわゆる PHP アプリケーション制作において役
    に立つ機能ではないと言われるのは、この辺。
    45

    View full-size slide

  45. とはいえ
    1リクエスト単位の視点でも非同期処理が役に立ちそうな
    ケースはある
    46

    View full-size slide

  46. 47
    例えば、APIリクエストを3回行
    う必要がある場合
    かつ、それぞれのAPIコールは
    相互に依存していない。

    View full-size slide

  47. 48
    こんな風に処理をまとめ
    られたら、効率的

    View full-size slide

  48. そういった用途には古来より curl_multi というものがある
    Fibers は別に使わなくても問題ない...
    49

    View full-size slide

  49. しかし、1リクエスト内でIO処理を束ねるようなケースは、そん
    なに多くない。
    レアケースに対して、本気に殴りに行くような改善よりも、もっと
    一般的なケースの改善をするほうが意味がある。
    50

    View full-size slide

  50. 1リクエスト単位で考えた場合
    PHPで非同期プログラミングを行うのは、あまり効果的である
    とは思えない。
    51

    View full-size slide

  51. JavaScript が基本的にノンブロッキングな処理を行う理由は、
    ブラウザを操作しているユーザーを待たせないため
    53

    View full-size slide

  52. 54
    JSのローディングイメージ例
    https://webdevtrick.com/lazy-load-images/

    View full-size slide

  53. ノンブロッキングを徹底することで、ブラウザ利用者の体験に
    寄与している。このへんはプログラミング言語の根本の思想に
    関わっている
    55

    View full-size slide

  54. 56
    複数リクエストの視点

    View full-size slide

  55. 話を単純化するために、CPUが1コアでウェブサーバーは1リ
    クエストずつ処理していくものとする。
    57

    View full-size slide

  56. 58
    1リクエストを以下のように図示する
    ※斜線部分は IO 以外の処理を行っているものとする

    View full-size slide

  57. 59
    通常の PHP ウェブアプリケーションでは
    リクエストはそれぞれ独立に直列で処理される

    View full-size slide

  58. 60
    いわゆる PHP ウェブサーバーの構成

    View full-size slide

  59. 今までの普通のPHPウェブアプリケーションでは、IO処理が
    もったいないと感じても、その間の資源を他に割り当てられな
    かった。
    61

    View full-size slide

  60. 62
    いわゆる PHP ウェブサーバーの構成
    Nginx も PHP-FPM も
    個別の PHP プロセスの処理状況を細かく
    監視できない

    View full-size slide

  61. もし、リクエストをまたいで非同期処理が行えたら、IO待ちの時
    に、他のリクエストを処理することで効率的にリクエストをさばく
    ことができる。
    63

    View full-size slide

  62. 実際に Fibers が利用が想定されているのは、リクエストをま
    たいだパターンが多そう
    リクエストをまたいで、処理の停止・実行を行うためには、全て
    のリクエスト処理が、PHPのメイン処理から実行されている必
    要がある
    65

    View full-size slide

  63. 66
    私が、PHP が PHP を実行する必要があると
    言っていたのはコレ。

    View full-size slide

  64. この世界観については、すでに Swoole 、 ReactPHP、
    AmPHP などで実現されている
    このように、PHPの主処理が停止せずにリクエストを実行して
    いくという処理パターンの文脈で
    イベントループがでてくる
    67

    View full-size slide

  65. 69
    Mastering Swoole PHP - Bruce Dou
    Swoole 作者による解説著作
    全体の2/3がPHPの処理モデル
    やIOモデルの説明となっていて、
    非同期を取り巻く状況を雑観でき
    る。

    View full-size slide

  66. ● 非同期処理とは
    ● 2つの視点
    ● イベントループ
    ● まとめ
    目次
    70

    View full-size slide

  67. 71
    イベントループとは?

    View full-size slide

  68. 72
    https://en.wikipedia.org/wiki/Event_loop
    イベントループの構成要素
    Wiki から想像して作図

    View full-size slide

  69. 73
    イベントループの構成要素
    リクエストはQueueで直列化される (DeMultiplex)

    View full-size slide

  70. 74
    イベントループの構成要素
    Event Loop 側はシングルスレッドで処理できる
    (Reactor Pattern)

    View full-size slide

  71. 75
    実装はループ処理
    例えば、配列にイベントが追加され
    ループで逐次処理されるのも、立派なイベントループ

    View full-size slide

  72. イベントループで実行されるEvent が Fiber オブジェクトになっ
    ていれば
    Suspend
    Restart
    をメインスレッドから抽象的に扱うことができる。
    76

    View full-size slide

  73. 77
    一番のポイント

    View full-size slide

  74. フレームワークの利用者側の視点で考えると
    同期的プログラミングを継続できる
    同期的プログラミングを行ったまま、非同期プログラミングの恩
    恵を受けることができる
    そんな非同期フレームワークを、Fibers を使うことで抽象的に
    理解しやすく作れる
    78

    View full-size slide

  75. 今後、Promise や Async/Await が PHP にもたらされる可能
    性はあるが、そもそも同期的であることに意味がある場合が多
    そうなので、利用シーンは限られそう
    79

    View full-size slide

  76. ● 非同期処理とは
    ● 2つの視点
    ● イベントループ
    ● まとめ
    目次
    80

    View full-size slide

  77. 非同期処理、Fibers、イベントループ
    この3つのキーワードがセットになって語られることが多いが、
    その理由はリクエストをまたいだ非同期処理を行うことが、
    PHPウェブアプリケーションにとって、もっとも現実的で徳が多
    そうだから
    81

    View full-size slide

  78. 82
    Fibers を使った Event Loop の例
    実装方法はたくさんある

    View full-size slide

  79. 実際は、ev拡張などを利用すれば、現状でもイベントループを
    簡単に書くことは出来る。
    Fibers はイベントループから実行された処理スレッドの停止・
    再開判断を抽象的に便利に行える機能と考えると分かりやす

    83

    View full-size slide

  80. 84
    とはいえ、書いてみないと実感しづらい

    View full-size slide

  81. 85
    雑なスライドだが実装サンプルを載せた
    https://speakerdeck.com/hanhan1978/fiber-and-async-request

    View full-size slide

  82. APIリクエストの非同期実行を
    生PHP -> Generator -> Fiber と抽象化していくサンプル
    Fibers は、抽象化の道具なんだね!が実感できる
    86

    View full-size slide

  83. @hanhan1978
    相談・指摘・その他 
    下記のTwitterアカウントにどうぞ
    87

    View full-size slide