Паралельність

Вступ

Іноді вам може знадобитися виконати кілька повільних завдань, які не залежать одне від одного. У багатьох випадках значні покращення продуктивності можна досягти, виконуючи завдання одночасно. Фасад 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'),
]);