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

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

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

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

F04982ad61107b5408ad139966596316?s=128

Ryo Tomidokoro

April 10, 2022
Tweet

More Decks by Ryo Tomidokoro

Other Decks in Technology

Transcript

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

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

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

  4. @hanhan1978 • 富所 亮 • 所属 株式会社カオナビ Expert • 職業

    Webアプリケーションエンジニア • ブログ https://blog.hanhans.net • Yokohama North AM https://anchor.fm/yokohama-north-am 4
  5. 前回までのあらすじ 5

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

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

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

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

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

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

  12. 3行でまとめると... - なぜ Fibers - イベントループってなに? - なぜ 非同期の仕組みがいまさらPHPに入ってくる? 12

    自信作だったが、スライドが荒かった
  13. 本日は合体整理版 13

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

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

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

    (初版.). オライリー・ジャパン.
  17. 17 PHPアプリケーションは 同期的なBlocking IOが基本

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

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

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

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

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

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

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

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

  26. 26 実行順序は直感と反する ① ③ ② 慣れれば分かるんだが ......

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

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

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

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

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

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

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

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

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

  36. 36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  52. 52 余談

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

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

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

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

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

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

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

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

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

  62. 62 いわゆる PHP ウェブサーバーの構成 Nginx も PHP-FPM も 個別の PHP

    プロセスの処理状況を細かく 監視できない
  63. もし、リクエストをまたいで非同期処理が行えたら、IO待ちの時 に、他のリクエストを処理することで効率的にリクエストをさばく ことができる。 63

  64. 64

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

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

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

  68. 68 余談

  69. 69 Mastering Swoole PHP - Bruce Dou Swoole 作者による解説著作 全体の2/3がPHPの処理モデル

    やIOモデルの説明となっていて、 非同期を取り巻く状況を雑観でき る。
  70. • 非同期処理とは • 2つの視点 • イベントループ • まとめ 目次 70

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

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

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

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

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

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

  77. 77 一番のポイント

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

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

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

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

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

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

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

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

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

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