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, and Fiber drivers.
  • If using the Fiber driver, you need to install composer require revolt/event-loop.
  • The Swoole or Swow driver can automatically coroutine the PHP blocking functions, allowing the previous synchronous code to be executed asynchronously.
  • However, Fiber cannot automatically coroutine like Swoole and Swow, and will block the entire process when encountering blocking functions built into PHP, with no context switching occurring.
  • When using Swoole, Swow, or Fiber drivers, Workerman automatically creates a coroutine to execute during each run of callbacks such as onWorkerStart, onMessage, onConnect, and onClose.
  • 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.