並行処理
イントロダクション
LaravelのConcurrencyファサードは、コミュニティからのフィードバックを収集中のため、現在ベータ版です。
互いに依存しない複数の遅いタスクを実行する必要がある場合があります。多くの場合、タスクを並行して実行することで、パフォーマンスを大幅に向上できます。LaravelのConcurrencyファサードは、クロージャを並行して実行するためのシンプルで便利なAPIを提供します。
並行処理の互換性
Laravel 10.xアプリケーションからLaravel 11.xにアップグレードした場合、アプリケーションのconfig/app.php設定ファイルのproviders配列にConcurrencyServiceProviderを追加する必要がある場合があります。
1'providers' => ServiceProvider::defaultProviders()->merge([ 2 /* 3 * Package Service Providers... 4 */ 5 Illuminate\Concurrency\ConcurrencyServiceProvider::class, 6 7 /* 8 * Application Service Providers... 9 */10 App\Providers\AppServiceProvider::class,11 App\Providers\AuthServiceProvider::class,12 // App\Providers\BroadcastServiceProvider::class,13 App\Providers\EventServiceProvider::class,14 App\Providers\RouteServiceProvider::class,15])->toArray(),
仕組み
Laravelは、指定されたクロージャをシリアライズし、非表示のArtisan CLIコマンドへディスパッチすることで並行処理を実現します。このコマンドはクロージャをアンシリアライズし、独自のPHPプロセス内で呼び出します。クロージャが呼び出された後、結果の値は親プロセスにシリアライズされて戻されます。
Concurrencyファサードは、process(デフォルト)、fork、syncの3つのドライバをサポートしています。
forkドライバは、デフォルトのprocessドライバよりも高いパフォーマンスを提供しますが、PHPがWebリクエスト中のフォークをサポートしていないため、PHPのCLIコンテキスト内でのみ使用できます。forkドライバを使用する前に、spatie/forkパッケージをインストールする必要があります。
1composer require spatie/fork
syncドライバは主に、すべての並行処理を無効にし、親プロセス内で指定されたクロージャを単に順番に実行したいテスト中に役立ちます。
並行タスクの実行
並行タスクを実行するには、Concurrencyファサードのrunメソッドを呼び出します。runメソッドは、子PHPプロセスで同時に実行する必要があるクロージャの配列を引数に取ります。
1use Illuminate\Support\Facades\Concurrency;2use Illuminate\Support\Facades\DB;3 4[$userCount, $orderCount] = Concurrency::run([5 fn () => DB::table('users')->count(),6 fn () => DB::table('orders')->count(),7]);
特定のドライバを使用するには、driverメソッドを使用します。
1$results = Concurrency::driver('fork')->run(...);
あるいは、デフォルトの並行処理ドライバを変更するには、config:publish Artisanコマンドでconcurrency設定ファイルを公開し、ファイル内のdefaultオプションを更新してください。
1php artisan config:publish concurrency
並行タスクの遅延実行
クロージャの配列を並行して実行したいが、それらのクロージャから返される結果には関心がない場合は、deferメソッドの使用を検討してください。deferメソッドが呼び出されると、指定されたクロージャはすぐには実行されません。代わりに、LaravelはHTTPレスポンスがユーザーに送信された後にクロージャを並行して実行します。
1use App\Services\Metrics;2use Illuminate\Support\Facades\Concurrency;3 4Concurrency::defer([5 fn () => Metrics::report('users'),6 fn () => Metrics::report('orders'),7]);