Green Thread

Green threads, also called goroutines in Go, virtual threads in Java 21+, or lightweight threads in Erlang/Haskell, are user-space threads managed entirely by the language runtime rather than the operating system kernel. The runtime multiplexes thousands or millions of them onto a small pool of OS threads, handles scheduling, stack growth, and context switching transparently, and makes blocking calls non-blocking without programmer intervention.

Key properties of native green threads:

  • Created with negligible overhead: a few kilobytes of stack, no syscall

  • Scheduled by the runtime, not the OS; the programmer spawns them freely without thinking about thread-pool sizing.

  • Blocking I/O is intercepted by the runtime and turned into a yield; other green threads run in the meantime.

  • No explicit await or suspend call is required at the call site: existing blocking code simply works.

Go goroutines are the canonical example: go fn() spawns a goroutine and returns immediately. The Go scheduler parks it when it blocks on I/O and resumes it when the I/O completes, across a fixed number of OS threads GOMAXPROCS.

PHP does not have native green threads. PHP’s default execution model is shared-nothing: each request runs in its own process or OS thread, managed by PHP-FPM or the web server, with no in-process concurrency between requests.

Available approximations, each with trade-offs:

  • Fibers, PHP 8.1: cooperative micro-threads within a single OS thread. Require explicit Fiber::suspend() / resume() call sites; the programmer must opt in at every yield point. Fibers do not run in parallel and do not intercept blocking I/O automatically.

  • Swoole / OpenSwoole / Swow: C extensions that replace PHP’s I/O layer and provide a coroutine scheduler. Within a Swoole coroutine server, blocking calls are transparently converted to non-blocking ones, closely approximating green-thread behaviour. However, this requires a persistent-process server model and is not part of the PHP standard distribution.

  • ReactPHP / AMPHP: pure-PHP event loops built on stream_select or libuv. They require explicit async/await, yield or async/await via Fibers, at every I/O boundary; there is no transparent interception.

  • parallel extension: true OS threads for CPU-bound work, with strict shared-state constraints: no shared objects.

None of these match the ergonomics of goroutines, where spawning a concurrent task is a single keyword and all existing synchronous I/O code continues to work unchanged.

<?php

    // PHP 8.1 Fibers: closest native approximation.
    // Unlike goroutines, suspension must be explicit and there is no parallelism.

    $fiber = new Fiber(function (): void {
        echo "Fiber started\n";
        $received = Fiber::suspend('first yield');  // explicit yield point required
        echo "Fiber resumed with: $received\n";
    });

    $yielded = $fiber->start();           // run until first suspend()
    echo "Main got: $yielded\n";         // 'first yield'
    $fiber->resume('hello');              // hand control back

    // Swoole coroutines (extension, not standard PHP) come closer
    // to transparent green threads:
    //
    // Co\run(function () {
    //     go(function () {
    //         // Co::sleep() suspends this coroutine transparently;
    //         // other coroutines run during the wait.
    //         Co::sleep(1);
    //         echo "task A done\n";
    //     });
    //     go(function () {
    //         Co::sleep(1);
    //         echo "task B done\n";
    //     });
    // });

?>

Documentation

See also Go: Goroutines, Java 21 Virtual Threads, Swoole coroutines, PHP Fibers RFC and AMPHP.

Related : Fibers, Coroutine, Concurrency, Asynchronous, Async, Multithreading, Thread, Green, OpenSwoole, Semaphore, Swoole

Related packages : amphp/amp, react/event-loop