Coroutines and event loops#

A coroutine is a thread of execution inside one interpreter: it has its own call stack, its own $_ and @_, its own local values, and it runs until it chooses to let another one run. Perl’s coroutine module is Coro; together with an event loop it lets a program wait on many sockets, timers and child processes at once while each task is written as plain straight-line code.

pperl runs Coro natively, with the event loops it is used with: EV, Event and AnyEvent, the layer that lets code run on any of them. Coro, EV and Event are part of the native-max module set; in a build without it, use Coro fails with Can't locate Coro.pm in @INC. AnyEvent, with its own pure-Perl loop, is in every standard build.

When to use them#

Coroutines are cooperative: one runs at a time, on one CPU, and a switch happens only where the code asks for one. That makes them the right tool for work that mostly waits - network clients and servers, pipelines of I/O stages, many timers - and the wrong one for work that computes. For compute-bound loops use auto-parallelisation; for isolated subprocesses use fork.

Because nothing is preemptive, there are no data races: a variable cannot change under you between two statements unless one of them switches. There are no locks to take for ordinary data either, only coordination primitives for waiting on each other.

Starting and switching#

async starts a coroutine; cede lets the others run; join waits for one to finish and returns its result:

use Coro;

my @workers = map {
    my $n = $_;
    async {
        for my $step (1 .. 3) {
            print "worker $n, step $step\n";
            cede;                       # let the others take a turn
        }
        return $n * 10;
    };
} 1 .. 2;

print "result: ", $_->join, "\n" for @workers;

The two workers alternate step by step. The main program is itself a coroutine ($Coro::main); $Coro::current is always the one running. A coroutine ends when its block returns, with terminate, or when another one calls $coro->cancel. An uncaught die inside a coroutine ends the whole program, as it would in the main program.

$coro->prio sets a priority from Coro::PRIO_MIN to Coro::PRIO_MAX (default PRIO_NORMAL); higher priorities always run first.

Waiting for each other#

Coro’s modules cover the usual coordination patterns:

  • Coro::Channel - a queue: put adds, get waits until there is something to take;

  • Coro::Semaphore - a counting semaphore, with down/up and a scope-bound guard;

  • Coro::Signal - wait until somebody sends a signal;

  • rouse callbacks - turn any callback into a wait: Coro::rouse_cb makes a callback, Coro::rouse_wait blocks until it is called and returns its arguments.

A producer and a consumer connected by a bounded channel:

use Coro;
use Coro::Channel;

my $queue = Coro::Channel->new(4);      # holds at most 4 items

my $producer = async {
    $queue->put($_) for 1 .. 10;
    $queue->put(undef);                 # end marker
};

while (defined(my $item = $queue->get)) {
    print "got $item\n";
}

Blocking on I/O with an event loop#

Coroutines pay off when a wait on a socket or a timer blocks only the coroutine that waits, not the program. That needs an event loop, and Coro::AnyEvent connects Coro to AnyEvent: whenever every coroutine is waiting, the loop runs until something is ready.

use Coro;
use Coro::AnyEvent;
use AnyEvent;

my @tasks = map {
    my ($name, $delay) = @$_;
    async {
        Coro::AnyEvent::sleep $delay;   # only this coroutine sleeps
        print "$name done after ${delay}s\n";
    };
} ["slow", 0.3], ["fast", 0.1];

$_->join for @tasks;

The same holds for files and sockets: Coro::Handle wraps a filehandle so that readline, read and print wait in the calling coroutine only, and Coro::Socket makes such handles for network connections. A server then handles each client in a coroutine of its own, written as if it were the only one.

Event loops#

AnyEvent chooses its loop the first time it needs one. A loop the program has already loaded wins; otherwise it loads the best one available, which in a native-max build is EV, and falls back to its own pure-Perl loop elsewhere. Code written against AnyEvent, and Coro code using Coro::AnyEvent, Coro::Handle or Coro::Socket, runs unchanged on any of them.

EV and Event can also be used directly, with callbacks:

use EV;

my $count = 0;
my $tick = EV::timer 0.1, 0.1, sub {    # after 0.1s, then every 0.1s
    print "tick ", ++$count, "\n";
    EV::break if $count == 3;
};

EV::run;                                # until EV::break

A watcher runs as long as the object EV::timer returned is alive; dropping the last reference stops it.

With coroutines, Coro::EV makes EV’s loop and Coro’s scheduler take turns, and adds waits of its own:

use Coro;
use Coro::EV;

async {
    Coro::EV::timer_once 0.2;           # this coroutine sleeps 0.2s
    print "woke up\n";
};

EV::run;                                # returns once nothing is left to wait for

Coro::Event does the same for Event, whose watchers block the coroutine that waits on them:

use Coro;
use Coro::Event;

async { Event::loop() };                # the event loop, in a coroutine of its own

my $timer = Coro::Event->timer(interval => 0.1);
for my $tick (1 .. 3) {
    $timer->next;                       # waits for the next tick
    print "tick $tick\n";
}

A Coro::Event watcher starts when something first waits on it, so the loop has to run alongside the code that waits, not before it.

What each coroutine has of its own#

Each coroutine has its own:

  • call stack and lexical variables (a sub can be running in several coroutines at once, each with its own my variables);

  • $_, @_, $@, $/ and the current regex match ($1 and friends);

  • local values - a local in one coroutine is not seen by the others;

  • $SIG{__DIE__} and $SIG{__WARN__}, and %^H.

Everything else is shared: package variables, $, and $\, open filehandles, and $a and $b - so two coroutines must not switch in the middle of a sort block that uses them in the same package.

C stacks#

Most switches cost no memory beyond the coroutine’s Perl-level stacks. A coroutine that switches away from inside a callback that the interpreter itself is running - a sort block, a tie method, a DESTROY, an overloaded operator - keeps a C stack of its own until it returns from there. Those stacks are 128 KiB each by default (Coro::State::cctx_stacksize sets the size, in pointers); code that recurses deeply inside such a callback, or through XS-level callbacks, may need more.

Porting from ithreads#

A thread per connection, or a work crew fed from a Thread::Queue, becomes a coroutine per connection, or coroutines fed from a Coro::Channel, with blocking I/O through Coro::Handle or Coro::AnyEvent. The :shared attributes and every lock go away: nothing else runs between two statements of a coroutine unless one of them switches. If the threads were there to use several CPUs for computation, coroutines are not the replacement - see Alternatives.

See also#

  • Coro and its modules - the full interface; pperl runs Coro 6.57’s own .pm files unchanged

  • Coro::State - the engine under Coro

  • EV and Event - the event loops, and Coro::EV, Coro::Event to run coroutines on them

  • AnyEvent - the event-loop abstraction most Coro programs use

  • Guard - run code when a scope ends, which Coro builds on

  • Alternatives - choosing between coroutines, auto-parallelisation and fork