Корутины
Корутин является более легковесным механизмом пользовательской параллельности по сравнению с потоками и позволяет реализовать многозадачное планирование в процессе. Это достигается за счет ручного управления приостановкой и восстановлением, что позволяет избежать накладных расходов на переключение контекста процесса.
Workerman предоставляет универсальный интерфейс корутин, который автоматически совместим с драйверами Swoole/Swow/Fiber на низком уровне.
Подсказка
Эта функция требует workerman>=5.1.0
Примечание
- Корутины поддерживают только драйверы
SwooleSwowFiber - При использовании драйвера
Fiberнеобходимо установитьcomposer require revolt/event-loop - Драйверы
SwooleилиSwowмогут автоматически корутинизировать блокирующие функции PHP, тем самым реализуя асинхронное выполнение изначально синхронного кода - Однако
Fiberне может автоматически корутинизировать, как это делаютSwooleиSwow, и при встрече с блокирующими функциями, встроенными в PHP, блокирует весь процесс, не производя переключения корутин - При использовании драйверов
SwooleSwowFiberкаждый раз, когдаworkermanвыполняет обратные вызовыonWorkerStartonMessageonConnectonCloseи т.д., автоматически создается корутина для выполнения - Можно использовать
$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.