Skip to main content

並行処理とは

複数の外部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 パッケージをインストールしてください。
fork ドライバはWebリクエスト中では動作しません。Artisanコマンドやキューワーカーの中で並行処理を行いたいときに使用してください。

実行結果を受け取らない: Concurrency::defer()

処理の結果には関心がなく、HTTPレスポンスを返した後にバックグラウンドで実行したい場合は defer() メソッドを使います。
defer() を呼んだ時点ではクロージャは実行されません。 HTTPレスポンスがユーザーに送信された後に、並行して実行されます。
分析データの記録やキャッシュのウォームアップなど、ユーザーを待たせる必要のない処理に defer() は最適です。

実践例: 複数の外部APIを同時に呼び出す

ECサイトのダッシュボードで、在庫管理API・売上集計API・配送状況APIの3つから情報を取得する例を考えます。

順次実行(改善前)

並行実行(改善後)

各APIが1秒かかる場合、順次実行では合計3秒かかりますが、並行実行では約1秒で完了します。

複数のデータベース集計を同時実行する

データベース集計に process ドライバを使う場合、子プロセスごとに新しいデータベース接続が確立されます。 同時実行数が多い場合はデータベースの最大接続数に注意してください。

テスト時の設定

テスト環境では sync ドライバを使うと、クロージャを順番に実行します。 並行実行によるプロセスの立ち上げコストがなく、テストが高速になります。
または .env.testing でデフォルトドライバを変更する方法もあります。

注意事項

クロージャはシリアライズされて子プロセスに渡されます。 シリアライズできないオブジェクト(データベース接続、ファイルハンドル、リソースなど)をクロージャの外側からキャプチャすることはできません。 必要なオブジェクトはクロージャの中で新たに生成してください。
process ドライバは子プロセスの起動コストがあるため、処理自体が非常に短い(数ミリ秒以下)場合は並行実行しても速くならないことがあります。 HTTPリクエストやデータベース集計など、処理に100ms以上かかるものを並行化するときに効果を発揮します。
fork ドライバはPHPのプロセスをforkするため、Webリクエスト中(FPMやApache)では使用できません。 Artisanコマンドやキューワーカーの中でのみ使用してください。
並行実行中に例外が発生すると、run() は例外を再スローします。 個々の処理で例外が発生しても他の処理を継続させたい場合は、クロージャの中で try/catch を使ってください。

次のステップ

キューとジョブ

処理をバックグラウンドで非同期実行するキューとジョブの使い方を学ぶ
最終更新日 2026年3月29日