並行処理とは
複数の外部APIへのリクエストやデータベースの集計処理など、互いに依存しない複数の処理を順番に実行すると、合計時間はそれぞれの処理時間の合計になります。 これらを同時に実行すれば、合計時間は最も時間のかかる処理1件分に短縮できます。 LaravelのConcurrency ファサードは、こうした並行実行をシンプルなAPIで実現します。
Concurrency ファサードはLaravel 11で導入され、Laravel 13でも引き続き利用できます。
デフォルトドライバは子PHPプロセスを使用するため、追加パッケージなしで動作します。仕組み
Concurrency ファサードは、渡されたクロージャをシリアライズして隠しArtisanコマンドに送り、それぞれ別のPHPプロセスとして実行します。
処理が完了すると戻り値をシリアライズして親プロセスに返します。
3つのドライバが用意されています。
基本的な使い方
Concurrency::run()
run() メソッドにクロージャの配列を渡すと、それらが並行実行されます。
戻り値は各クロージャの返した値を配列で受け取ります。
ドライバの指定
特定のドライバを使いたい場合はdriver() メソッドで指定します。
default オプションを更新します。
forkドライバの使い方
fork ドライバは process ドライバよりも高速ですが、PHPのCLI環境(Artisanコマンドやキューワーカー)でのみ使用できます。
Webリクエストの中では使用できません。
使用前に spatie/fork パッケージをインストールしてください。
実行結果を受け取らない: Concurrency::defer()
処理の結果には関心がなく、HTTPレスポンスを返した後にバックグラウンドで実行したい場合はdefer() メソッドを使います。
defer() を呼んだ時点ではクロージャは実行されません。
HTTPレスポンスがユーザーに送信された後に、並行して実行されます。
実践例: 複数の外部APIを同時に呼び出す
ECサイトのダッシュボードで、在庫管理API・売上集計API・配送状況APIの3つから情報を取得する例を考えます。順次実行(改善前)
並行実行(改善後)
複数のデータベース集計を同時実行する
テスト時の設定
テスト環境ではsync ドライバを使うと、クロージャを順番に実行します。
並行実行によるプロセスの立ち上げコストがなく、テストが高速になります。
.env.testing でデフォルトドライバを変更する方法もあります。
注意事項
クロージャにできる制限
クロージャにできる制限
クロージャはシリアライズされて子プロセスに渡されます。
シリアライズできないオブジェクト(データベース接続、ファイルハンドル、リソースなど)をクロージャの外側からキャプチャすることはできません。
必要なオブジェクトはクロージャの中で新たに生成してください。
processドライバのオーバーヘッド
processドライバのオーバーヘッド
process ドライバは子プロセスの起動コストがあるため、処理自体が非常に短い(数ミリ秒以下)場合は並行実行しても速くならないことがあります。
HTTPリクエストやデータベース集計など、処理に100ms以上かかるものを並行化するときに効果を発揮します。forkドライバの制限
forkドライバの制限
fork ドライバはPHPのプロセスをforkするため、Webリクエスト中(FPMやApache)では使用できません。
Artisanコマンドやキューワーカーの中でのみ使用してください。例外の扱い
例外の扱い
並行実行中に例外が発生すると、
run() は例外を再スローします。
個々の処理で例外が発生しても他の処理を継続させたい場合は、クロージャの中で try/catch を使ってください。次のステップ
キューとジョブ
処理をバックグラウンドで非同期実行するキューとジョブの使い方を学ぶ