Coroutine
Coroutine is a lightweight user-level concurrency mechanism that is lighter than threads and enables multitasking scheduling within a process. It achieves context switching between coroutines through manual control of suspension and resumption, thus avoiding the overhead of process context switching. Workerman provides a universal coroutine interface that is automatically compatible with Swoole/Swow/Fiber drivers at the underlying level.
Tip
This feature requires workerman >= 5.1.0
Note
- Coroutines only support
Swoole,Swow, andFiberdrivers. - If using the
Fiberdriver, you need to installcomposer require revolt/event-loop. - The
SwooleorSwowdriver can automatically coroutine the PHP blocking functions, allowing the previous synchronous code to be executed asynchronously. - However,
Fibercannot automatically coroutine likeSwooleandSwow, and will block the entire process when encountering blocking functions built into PHP, with no context switching occurring. - When using
Swoole,Swow, orFiberdrivers, Workerman automatically creates a coroutine to execute during each run of callbacks such asonWorkerStart,onMessage,onConnect, andonClose. - You can set different coroutine drivers for different workers using
$worker->eventLoop = xxx;.
<?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; // Using Swoole coroutines
$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; // Using built-in Fiber coroutines
$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();
Interfaces Provided by Coroutines
interface CoroutineInterface
{
/**
* Create a coroutine and execute it immediately
*/
public static function create(callable $callable, ...$data): CoroutineInterface;
/**
* Start the coroutine running
*/
public function start(mixed ...$args): mixed;
/**
* Resume the coroutine execution
*/
public function resume(mixed ...$args): mixed;
/**
* Get the coroutine id
*/
public function id(): int;
/**
* Set a callback to be called when the coroutine is destroyed
*/
public static function defer(callable $callable): void;
/**
* Suspend the current coroutine
*/
public static function suspend(mixed $value = null): mixed;
/**
* Get the current coroutine
*/
public static function getCurrent(): CoroutineInterface|Fiber|SwowCoroutine|static;
/**
* Determine if the current environment is a coroutine
*/
public static function isCoroutine(): bool;
}
About Coroutines
Advantages
The greatest benefit of introducing coroutines in PHP is that it allows you to write asynchronous code in a synchronous manner, avoiding callback hell and improving code readability and maintainability. Coroutines can significantly enhance the elasticity of I/O-intensive tasks, allowing for greater throughput with fewer processes.
Disadvantages
However, with the introduction of coroutines, developers need to constantly pay attention to issues such as global variable pollution, resource competition, and third-party library modifications, which increases development and maintenance costs and significantly raises the mental burden.
The introduction of coroutines incurs additional overhead related to coroutine creation, scheduling, destruction, and connection pools. According to extensive performance testing data, under full CPU utilization, the extreme performance with coroutines is about 10%-20% lower than that with blocking I/O.