Через фасад Concurrency - він запускає замикання одночасно й повертає результати в тому самому порядку.
use Illuminate\Support\Facades\Concurrency;
[$userCount, $orderCount, $rates] = Concurrency::run([
fn () => DB::table('users')->count(),
fn () => DB::table('orders')->count(),
fn () => Http::get('https://api.example.com/rates')->json(),
]);
Якщо кожна операція триває секунду, послідовно це три секунди, паралельно - близько однієї.
Як це працює: драйвер за замовчуванням process серіалізує кожне замикання й виконує його в окремому дочірньому процесі PHP через Artisan. Є драйвер fork (швидший, лише CLI, потрібен пакет spatie/fork) і sync для тестів.
Обмеження:
- кожен дочірній процес завантажує застосунок - на коротких операціях ці накладні витрати з'їдають виграш;
- замикання серіалізуються: не можна захоплювати те, що не серіалізується (з'єднання, ресурси,
$thisскладного об'єкта); - результат має бути серіалізованим.
Альтернативи:
- кілька HTTP-запитів -
Http::pool(), без нових процесів; - робота, результат якої не потрібен відповіді, -
Concurrency::defer()або черга.
Найчастіше це доречно для дашбордів з кількома незалежними важкими агрегаціями чи для зведення даних з кількох зовнішніх API.