並行処理
はじめに
Laravelの`Concurrency`ファサードは、現在ベータ版であり、コミュニティからのフィードバックを収集しています。
互いに依存しない、複数の低速タスクを実行する必要がある場合があります。多くの場合、タスクを並行して実行することで、パフォーマンスを大幅に向上させることができます。Laravelの`Concurrency`ファサードは、クロージャを並行して実行するためのシンプルで便利なAPIを提供します。
並行処理の互換性
Laravel 10.xアプリケーションからLaravel 11.xにアップグレードした場合、アプリケーションの`config/app.php`設定ファイルの`providers`配列に`ConcurrencyServiceProvider`を追加する必要がある場合があります。
'providers' => ServiceProvider::defaultProviders()->merge([ /* * Package Service Providers... */ Illuminate\Concurrency\ConcurrencyServiceProvider::class, /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class,])->toArray(),
仕組み
Laravelは、指定されたクロージャをシリアライズし、非表示のArtisan CLIコマンドにディスパッチすることで並行処理を実現します。このコマンドは、クロージャをデシリアライズし、独自のPHPプロセス内で呼び出します。クロージャが呼び出された後、結果の値は親プロセスにシリアライズされて返されます。
`Concurrency`ファサードは、`process`(デフォルト)、`fork`、`sync`の3つのドライバをサポートしています。
`fork`ドライバは、デフォルトの`process`ドライバと比較してパフォーマンスが向上しますが、PHPのCLIコンテキスト内でのみ使用できます。これは、PHPがウェブリクエスト中のフォークをサポートしていないためです。`fork`ドライバを使用する前に、`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` Artisanコマンドを使用して`concurrency`設定ファイルを公開し、ファイル内の`default`オプションを更新する必要があります。
php artisan config:publish concurrency
並行タスクの遅延
クロージャの配列を並行して実行したいが、それらのクロージャによって返される結果には関心がない場合は、`defer`メソッドの使用を検討してください。`defer`メソッドが呼び出されると、指定されたクロージャはすぐに実行されません。代わりに、Laravelは、HTTPレスポンスがユーザーに送信された後に、クロージャを並行して実行します。
use App\Services\Metrics;use Illuminate\Support\Facades\Concurrency; Concurrency::defer([ fn () => Metrics::report('users'), fn () => Metrics::report('orders'),]);