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

大解剖!amphpを使って非同期 PHP を実現しよう!

大解剖!amphpを使って非同期 PHP を実現しよう!

PHPカンファレンス2023登壇資料です。

Masaru Yamagishi

October 07, 2023
Tweet

More Decks by Masaru Yamagishi

Other Decks in Programming

Transcript

  1. 大解剖! amphp を使って非同期 PHP を
    実現しよう!
    2023/10/08 PHP カンファレンス 2023 やまゆ

    View full-size slide

  2. セッション概要
    PHP はデータベース通信、ファイル操作などの I/O バウンドなユースケースで多く使われています。
    これまでの PHP では I/O 処理でブロックし、処理が終わるまで待機する仕組みになっていましたが、
    PHP 8.1 から Fiber がコア実装に含まれたことにより、 PHP でも非同期な処理をサードパーティ
    extension なしでより簡単に実装することが出来るようになりました。
    中でも注目を集めるライブラリ群が amphp です。このライブラリ群は、 HTTP サーバや MySQL クエリの
    非同期化など様々な高レベル実装を提供しています。
    今回は、現段階で実装済みの各ライブラリを紹介し、今後
    PHP でも非同期処理を使いやすくなるぞ、と
    いうことを紹介したいと思います。

    View full-size slide

  3. 赤魔道士系エンジニア
    ㈱インフィニットループ at 札幌/仙台 

    やまゆ
    この画像は自撮りでも
    いつも使っているアイコンでも構いません



    View full-size slide

  4. もくじ
    1. 同期と非同期
    a. 同期と非同期
    b. 並列と並行
    c. Promise と Future
    d. async と await
    2. PHP における非同期処理
    a. Fiber(イベントループ)
    b. Revolt
    c. amphp
    3. amphp における非同期処理
    4. amphp のユースケース
    1. amphp における非同期処理
    a. ライブラリ構成図
    b. amphp/amp
    c. amphp/log
    d. amphp/file
    e. amphp/socket
    f. amphp/http-client
    g. amphp/http-server
    h. amphp/parallel
    i. amphp/sync
    j. amphp/mysql
    k. amphp/websocket-client
    l. amphp/websocket-server

    View full-size slide

  5. 同期と非同期

    View full-size slide

  6. 同期と非同期とは
    同期=直列的, 非同期=並列的
    同期シーケンス 非同期シーケンス

    View full-size slide

  7. 非同期処理における並行 & 並列
    非同期処理には種類がある
    - 並行(Concurrency)
    - 並列(Parallelism)
    言語の仕組みによって並行性が高かったり並列性が高かったりする
    言語だけでなくドキュメントでもこの表現は揺れているので、今回の資料では
    - 並行=シングルスレッドでうまいこと非同期する
    - 並列=マルチスレッド・マルチプロセスで非同期する
    とする(わかりやすくするため。これが正解というわけではない)。

    View full-size slide

  8. PHP は(基本的に)シングルスレッド
    なので「並列」ではなく「並行」が近い
    マルチプロセスは可能だが、プロセス間通信はちょっと大変
    マルチスレッドは extension を使えば可能(zts ビルド必須)
    今回紹介するのは「並行処理」

    View full-size slide

  9. JavaScript も(基本的に)シングルスレッド=並行

    View full-size slide

  10. Promise と Future
    非同期な処理の実行を開始した直後は、まだ実行が終わっていないので実行結果を
    受け取ることが出来ません。
    そこで、 Promise や Future といった「多分まだ終わっていないが、そのうち終わる」プ
    レースホルダーのようなオブジェクトを受け取ります。
    このプレースホルダーの名称や挙動は言語やライブラリにより異なりますが、大体「後
    で非同期処理結果を取得するためのもの」です。

    View full-size slide

  11. async と await
    Promise や Future だと取り回しがしづらい場合があります。それを解決するために、言
    語やライブラリに async/await 処理が追加されている場合があります。

    View full-size slide

  12. async/await について
    JavaScript の変遷をたどると分かりやすい
    SoftwareDesign 2023年9月号に詳しく載ってます!
    (他人の記事を勝手に宣伝)
    https://gihyo.jp/magazine/SD/archive/2023/202309

    View full-size slide

  13. PHP における
    非同期処理

    View full-size slide

  14. 何故 PHP は非同期に基本非対応だったか?
    元々 PHP を非同期に処理する仕組みは公式には提供されていませんでした。
    PHP はあくまで HTML 文字列を随時出力しながら演算する言語だったからです。
    既に出力された文字列はクライアントに見えてしまうので、そこで後で非同期にしてもほ
    とんど意味がありませんでした。
    最近は json でまとめて返すことが増えたので、ユースケースとして現れるようになった
    形です。

    View full-size slide

  15. Fiber による問題解決
    https://www.php.net/manual/ja/language.fibers.php
    Fiber はコルーチンと呼ばれるような「完全なスタックを持つ停止可能な関数」で、どこ
    からでも実行スタックを停止することが出来るようになります。
    PHP 8.1+ で利用可能です。

    View full-size slide

  16. わからん
    🤔

    View full-size slide

  17. 結局何が出来るのか?
    他の言語で非同期について詳しい方は「はぁ~なるほど」となるかもしれませんが、今
    まで PHP をメインで追っていた方は、「実行スタック?を止めてどうすんねん」となるか
    と思います。私も正直深くは分かってないです。だれか教えて。
    今回は割愛しますが、この機能があることで「Aの実行を待っている間にBをする」が出
    来るようになります。いわゆるこれが非同期です。

    View full-size slide

  18. Revolt
    Fiber のコールスタックを管理してくれる低レベル API ライブラリ
    - Defer: go の defer のように、イテレーションの最後に
    - Delay: x 秒後に
    - Repeat: x 秒おきに
    - Stream readable: ストリームが読み込めるようになったら
    - Stream writable: ストリームに書きこめるようになったら
    - Signal: プロセスシグナルを OS から受け取ったら

    View full-size slide

  19. シンプルすぎて
    わからん
    🤔

    View full-size slide

  20. amphp が解決する課題
    Fiber, Revolt は「ライブラリ作成者向けの低レベル API」です。普段のアプリ開発で直
    接利用することはあまり想定されていません。
    それらを利用して、アプリ開発レベルまで高レベル化したライブラリが amphp です。
    複数のパッケージとして開発されているライブラリ群で、 async/await のみならず、
    HTTP サーバ、 MySQL クエリ、ロギングなど様々な同期処理を非同期化してくれま
    す。

    View full-size slide

  21. amphp における
    非同期処理

    View full-size slide

  22. amphp/amp
    ベース of ベースとなる中核ライブラリ
    - v1.0(-2017) は while ループや third-party extension を利用した実装
    - v2.0(-2022) も同様で、 event-loop を素直に実装したもの
    - v3.0(2022-) は Fiber(PHP8.1+) を利用したものに大きく変更

    View full-size slide

  23. amphp/amp
    v3.0 は「キャンセル可能な async/await を
    Revolt ベースで実装」している
    ほぼ全ての上位ライブラリはこの
    async/await を活用した実装となっている
    非常にシンプルなインターフェースを提供

    View full-size slide

  24. ライブラリ構成一覧
    - amphp/amp: もちろん全て async な処理
    - byte-stream: ストリーム処理
    - process: 子プロセス
    - file: ファイル操作
    - pipeline: イテレータ
    - sync: Mutex による同期
    - parallel: “並列” 処理
    - log: MonologHandler
    - socket: TCP/UDP ソケット通信
    - http-server: TLS, HTTP/2 対応 HTTP サーバ
    - http-client: TLS, HTTP/2 対応 HTTP クライアント
    - http-tunnel: Proxy HTTP 通信
    - websocket-client: WebSocket クライアント
    - websocket-server: WebSocket サーバ
    - redis: Redis 操作
    - postgres: PostgreSQL 操作
    - mysql: MySQL 操作
    - internal: 内部で利用される
    - sql: SQL の抽象化
    - cache: キャッシュの抽象化
    - parser: パーサの抽象化
    - serialization: シリアライズの抽象化
    - http: HTTP 通信の基本実装
    - websocket: WebSocket 通信の基本実装
    - phpunit-util: PHPUnit サポート
    - hpack: HTTP/2 用実装

    View full-size slide

  25. iterable や resource の書きこみ・読み込みをブロックせずに処理する
    様々なストリーム処理のベース
    byte-stream: ストリーム処理

    View full-size slide

  26. process: 子プロセス
    子プロセスをブロックせずに処理する

    View full-size slide

  27. file: ファイル操作
    ファイル操作をブロックせずに処理する

    View full-size slide

  28. pipeline: イテレータ
    iterable を並行で一気に処理する

    View full-size slide

  29. sync: 同期
    複数の非同期処理で進行をロック

    View full-size slide

  30. parallel: “並列” 処理
    プロセス(またはスレッド)を利用して “真の並列処理” を実行する

    View full-size slide

  31. log: MonologHandler
    シンプルに Monolog のストリーム書きこみを非同期に処理する

    View full-size slide

  32. socket: TCP/UDP ソケット通信
    RAW TCP/UDP ソケット通信をブロックせずに処理する

    View full-size slide

  33. http-server: HTTP サーバ
    シンプルな API で HTTP(S) サーバ

    View full-size slide

  34. http-client: HTTP クライアント
    HTTP リクエストを
    非同期に処理する

    View full-size slide

  35. websocket-
    server:
    WebSocket
    サーバ
    シンプルな API で
    WebSocket(s) サーバ

    View full-size slide

  36. websocket-client: WebSocket クライアント
    WebSocket コネクションを処理する
    (※これはまだベータ版)

    View full-size slide

  37. redis: Redis 操作
    Redis の操作をブロックせずに処理する

    View full-size slide

  38. postgres: PostgreSQL 操作
    PostgreSQL へのクエリをブロックせずに処理する
    (※これはまだベータ版)

    View full-size slide

  39. mysql: MySQL 操作
    MySQL クエリをブロックせずに処理する
    (※これはまだベータ版)

    View full-size slide

  40. amphp の
    ユースケース

    View full-size slide

  41. WebSocket による ChatBOT
    - ロングプロセスモデルで WebSocket client/server の実装
    - Slack や LINE などのリアルタイム通信を golang や node.js のように
    - 実装側はほとんど非同期を意識しなくていいので楽
    - BotMan のようなフレームワークでそう

    View full-size slide

  42. Pure-PHP HTTP/2(TLS) サーバ
    - nginx, php-fpm, apache などを使わず PHP だけで HTTP(S) サーバ
    - TLS や HTTP/2 も対応!
    - 障害点が減るので嬉しいかも
    - まだ大規模利用実績はないので、誰かやってみてください(丸投げ)

    View full-size slide

  43. 大量並行・並列処理のマネジメント
    - バッチ処理をスケールさせる
    - クエリをスケールさせる
    - Cluster や RPC なども開発中
    - 既存の重い処理を一部だけ非同期化して高速化
    - パフォーマンスチューニングが捗る

    View full-size slide

  44. まとめ
    amphp は いいぞ。
    - PHP でも非同期、簡単に出来るようになりました!
    - amphp をベースとしたフレームワークが出そう
    - 世は大 Pure-PHP 時代
    - 局所的な遅い I/O ループの改善にいかが?

    View full-size slide

  45. 次は北海道で
    会いましょう!

    View full-size slide

  46. https://www.infiniteloop.co.jp

    View full-size slide