Корутины

Корутин является более легковесным механизмом пользовательской параллельности по сравнению с потоками и позволяет реализовать многозадачное планирование в процессе. Это достигается за счет ручного управления приостановкой и восстановлением, что позволяет избежать накладных расходов на переключение контекста процесса.
Workerman предоставляет универсальный интерфейс корутин, который автоматически совместим с драйверами Swoole/Swow/Fiber на низком уровне.

Подсказка
Эта функция требует workerman>=5.1.0

Примечание

  • Корутины поддерживают только драйверы Swoole Swow Fiber
  • При использовании драйвера Fiber необходимо установить composer require revolt/event-loop
  • Драйверы Swoole или Swow могут автоматически корутинизировать блокирующие функции PHP, тем самым реализуя асинхронное выполнение изначально синхронного кода
  • Однако Fiber не может автоматически корутинизировать, как это делают Swoole и Swow, и при встрече с блокирующими функциями, встроенными в PHP, блокирует весь процесс, не производя переключения корутин
  • При использовании драйверов Swoole Swow Fiber каждый раз, когда workerman выполняет обратные вызовы onWorkerStart onMessage onConnect onClose и т.д., автоматически создается корутина для выполнения
  • Можно использовать $worker->eventLoop=xxx;, чтобы назначить разные драйверы корутин для различных worker
<?php
use Workerman\Connection\TcpConnection;
use Workerman\Coroutine;
use Workerman\Events\Swoole;
use Workerman\Events\Fiber;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';

$worker1 = new Worker('http://0.0.0.0:8001');
$worker1->eventLoop = Swoole::class; // Используем корутины Swoole
$worker1->onMessage = function (TcpConnection $connection, Request $request) {
    Coroutine::create(function () {
        echo file_get_contents("http://www.example.com/event/notify");
    });
    $connection->send('ok');
};

$worker2 = new Worker('http://0.0.0.0:8001');
$worker2->eventLoop = Fiber::class; // Используем встроенные корутины Fiber
$worker2->onMessage = function (TcpConnection $connection, Request $request) {
    Coroutine::create(function () {
        echo file_get_contents("http://www.example.com/event/notify");
    });
    $connection->send('ok');
};

Worker::runAll();

Интерфейс, предоставляемый корутинами

interface CoroutineInterface
{

    /**
     * Создает корутину и немедленно выполняет ее
     */
    public static function create(callable $callable, ...$data): CoroutineInterface;

    /**
     * Начинает выполнение корутины
     */
    public function start(mixed ...$args): mixed;

    /**
     * Возобновляет выполнение корутины
     */
    public function resume(mixed ...$args): mixed;

    /**
     * Получает ID корутины
     */
    public function id(): int;

    /**
     * Устанавливает обратный вызов при уничтожении корутины
     */
    public static function defer(callable $callable): void;

    /**
     * Приостанавливает текущую корутину
     */
    public static function suspend(mixed $value = null): mixed;

    /**
     * Получает текущую корутину
     */
    public static function getCurrent(): CoroutineInterface|Fiber|SwowCoroutine|static;

    /**
     * Проверяет, находится ли в текущей среде выполнение корутин
     */
    public static function isCoroutine(): bool;

}

О корутинах

Преимущества

Главное преимущество ввода корутин в PHP заключается в том, что можно писать асинхронный код в синхронном стиле, избегая "ада коллбеков", что значительно улучшает читаемость и поддерживаемость кода.
Корутины могут значительно увеличить устойчивость I/O-нагруженных задач, позволяя с меньшим количеством процессов обеспечивать большую пропускную способность.

Недостатки

Однако, ввод корутин требует от разработчиков постоянного внимания к таким проблемам, как загрязнение глобальных переменных, конкуренция за ресурсы, модификация сторонних библиотек и т.д., что увеличивает затраты на разработку и повышает умственную нагрузку.

Ввод корутин также создает дополнительные накладные расходы на создание, планирование, уничтожение корутин, пул соединений и т.д.
Согласно данным многочисленных нагрузочных тестов, в условиях полной загрузки процессора производительность с корутинами, как правило, снижается примерно на 10%-20% по сравнению с блокирующим I/O.