コンテンツにスキップ

並行処理

はじめに

exclamation

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'),
]);