Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

赤魔道士系エンジニア ㈱インフィニットループ at 札幌/仙台 
 やまゆ この画像は自撮りでも いつも使っているアイコンでも構いません ☕

Slide 4

Slide 4 text

もくじ 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

Slide 5

Slide 5 text

同期と非同期

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

PHP における 非同期処理

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Fiber

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

わからん 🤔

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Revolt

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

amphp

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

amphp における 非同期処理

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

ライブラリ構成一覧 - 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 用実装

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

amphp の ユースケース

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

まとめ

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

https://www.infiniteloop.co.jp