Паралельність
Вступ
Іноді вам може знадобитися виконати кілька повільних завдань, які не залежать одне від одного. У багатьох випадках значні покращення продуктивності можна досягти, виконуючи завдання одночасно. Фасад Laravel Concurrency надає простий і зручний API для одночасного виконання замикань.
Як це працює
Laravel досягає паралельності шляхом серіалізації наданих замикань і відправлення їх до прихованої Artisan CLI команди, яка десеріалізує замикання і викликає їх у власному PHP процесі. Після виклику замикання, отримане значення серіалізується назад до батьківського процесу.
The Concurrency фасад підтримує три драйвери: process (за замовчуванням), fork і sync.
The fork драйвер пропонує покращену продуктивність у порівнянні з драйвером за замовчуванням process, але його можна використовувати лише в контексті CLI PHP, оскільки PHP не підтримує форкування під час веб-запитів. Перед використанням драйвера fork, вам потрібно встановити пакет spatie/fork:
composer require spatie/fork
Драйвер sync є переважно корисним під час тестування, коли ви хочете вимкнути всю паралельність і просто виконати задані замикання послідовно в межах батьківського процесу.
Запуск паралельних завдань
Щоб виконувати паралельні завдання, ви можете викликати метод run фасаду Concurrency. Метод 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(...);
Або, щоб змінити драйвер паралельності за замовчуванням, ви повинні опублікувати файл конфігурації concurrency за допомогою команди Artisan config:publish і оновити опцію 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'),
]);
