同時に動かす(並行処理)
時間のかかる、おたがいに関係のない処理を同時に動かして速くする、Concurrency の使い方とドライバー、結果の名前、タイムアウトを説明します。
並行処理(同時に動かすこと)は、時間のかかる仕事をいっせいに始めて、待ち時間を短くするしくみです。たとえば、3人で別々の掃除を同時に始めれば、1人で順番にやるより早く終わります。たがいに関係のない、遅い処理がいくつかあるときに、使えます。Laravel の Concurrency ファサード(Route::get() のように、クラス名と :: で機能を呼べる窓口)で、関数(クロージャ)を同時に動かせます。
しくみとドライバー#
Laravel は、渡された関数を、シリアライズ(文字などの形に変えて、あとで元に戻せるようにすること)して、一覧には出ない、隠れた Artisan コマンド(php artisan で動かすコマンド)へ送ります。そのコマンドが、関数を元に戻し、自分の PHP のプロセス(動いているプログラム)で動かします。動かし終わったら、結果をシリアライズして、元のプロセスへ返します。
Concurrency には、3つのドライバー(動かし方の種類)があります。process(はじめの設定)・fork・sync です。
| ドライバー | 説明 |
|---|---|
process |
はじめの設定。関数を別の PHP のプロセスで動かす |
fork |
process より速い。PHP の CLI(ターミナルで動かすとき)でだけ使える |
sync |
同時には動かさず、元のプロセスで順番に動かす。テストのときに便利 |
fork は、process より速くなります。ただし、PHP は Web のリクエストの中ではフォーク(プロセスを複製すること)ができないので、CLI の中でしか使えません。使う前に、spatie/fork パッケージを入れます。
composer require spatie/fork
sync は、おもにテストで使います。同時には動かさず、渡された関数を、元のプロセスで順番に動かします。
同時に動かす#
同時に動かすには、Concurrency ファサードの run メソッドを呼びます。run は、関数の配列を受け取り、それらを PHP の子のプロセス(元のプロセスから作られた、別のプロセス)で同時に動かします。
use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\DB;
[$userCount, $orderCount] = Concurrency::run([
fn () => DB::table('users')->count(),
fn () => DB::table('orders')->count(),
]);
ドライバーを決めるには、driver メソッドを使います。
$results = Concurrency::driver('fork')->run(...);
はじめのドライバーを変えたいときは、config:publish コマンドで、concurrency の設定ファイルを取り出して、その中の default を直します。
php artisan config:publish concurrency
結果に名前を付ける#
結果を、順番ではなく、名前で取り出したいときは、キーを付けた配列(連想配列)で、関数を渡します。結果は、対応する関数と同じキーで返ります。
use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\DB;
$results = Concurrency::run([
'users' => fn () => DB::table('users')->count(),
'orders' => fn () => DB::table('orders')->count(),
]);
$userCount = $results['users'];
$orderCount = $results['orders'];
時間の制限(タイムアウト)#
process ドライバー(はじめの設定)のときは、run に時間の制限(タイムアウト)を渡せます。決めた秒数がすぎても終わらない処理は、止められます。
use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\DB;
[$userCount, $orderCount] = Concurrency::run([
fn () => DB::table('users')->count(),
fn () => DB::table('orders')->count(),
], timeout: 30);
分かりやすく書きたいときは、CarbonInterval(時間の長さを表すオブジェクト)も渡せます。
use Illuminate\Support\Facades\Concurrency;
use function Illuminate\Support\seconds;
Concurrency::run([...], timeout: seconds(30));
あとで同時に動かす#
関数を同時に動かしたいけれど、結果は要らないときは、defer メソッドが使えます。defer を呼んでも、すぐには動きません。ユーザーへ HTTP のレスポンス(サーバーが返す答え)を送ったあとに、Laravel が同時に動かします。
use App\Services\Metrics;
use Illuminate\Support\Facades\Concurrency;
Concurrency::defer([
fn () => Metrics::report('users'),
fn () => Metrics::report('orders'),
]);
| メソッド | 説明 |
|---|---|
run |
関数を同時に動かし、結果を返す(timeout で時間の制限を決められる) |
driver |
使うドライバーを決める |
defer |
レスポンスを送ったあとで、関数を同時に動かす(結果は受け取らない) |
関連するページ#
公式ドキュメント(英語)
2026年10月5日時点の内容をもとに、日本語でまとめています。