はじめに
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プロセス内で呼び出します。クロージャが呼び出された後、結果の値は親プロセスにシリアライズされて戻されます。
`````fork`````ドライバーは、デフォルトの`````process`````ドライバーと比較してパフォーマンスが向上しますが、PHPのCLIコンテキスト内でのみ使用できます。なぜなら、PHPはWebリクエスト中にフォークをサポートしていないからです。`````fork`````ドライバーを使用する前に、`````spatie/fork`````パッケージをインストールする必要があります:
``````bash
composer require spatie/fork
`
<a name="running-concurrent-tasks"></a>
## 同時タスクの実行
同時タスクを実行するには、`````Concurrency`````ファサードの`````run`````メソッドを呼び出すことができます。`````run`````メソッドは、子PHPプロセス内で同時に実行されるべきクロージャの配列を受け取ります:
``````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(...);
または、デフォルトの同時実行ドライバーを変更するには、concurrency
設定ファイルをconfig:publish
Artisanコマンドを介して公開し、ファイル内の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'),
]);