Concurrency

Promises, supplies & channels

Full

Raku's high-level concurrency — start/await, react/whenever, and Channels.

Interpreter Native (--exe) Browser

Raku++ implements Raku's high-level concurrency: start runs a block on another thread and hands back a Promise, await waits for results, and react/whenever consume asynchronous Supply streams. These run in the Raku++ interpreter and the --exe native binary, matching Rakudo — but the in-browser playground is single-threaded, so the examples here are shown with their verified output rather than a Run button (see Execution modes for why).

start and await #

start { … } schedules the block on the thread pool and returns a Promise; await blocks until it resolves and yields the value.

not in browser
my $p = start { 40 + 2 };
say await $p;
Output
42

Several run concurrently; awaiting each collects its result.

not in browser
my $a = start { 2 + 2 };
my $b = start { 3 * 3 };
say await($a) + await($b);
Output
13

react / whenever #

A react block sits and responds to events; each whenever subscribes to a Supply and runs its body per emitted value.

not in browser
react {
    whenever Supply.from-list(10, 20, 30) -> $v {
        say $v;
    }
}
Output
10
20
30

Waiting on many promises #

Promise.allof completes once every promise in a list has — then each .result is ready.

not in browser
my @p = (1..3).map(-> $n { start { $n * 10 } });
await Promise.allof(@p);
say @p.map(*.result);
Output
(10 20 30)

Producing a Promise — vow #

start gives you a Promise that some code fulfils. To create and fulfil one by hand, take its vow (the private write-capability) and .keep it with a value — or .break it with a failure.

not in browser
my $p = Promise.new;
my $v = $p.vow;
$v.keep(42);
say await $p;
Output
42

.break moves the Promise to the Broken status; awaiting a broken Promise rethrows.

not in browser
my $p = Promise.new;
$p.vow.break("nope");
say $p.status;
Output
Broken

Guarding shared state — Lock #

When several threads touch the same data, a Lock serialises access: .protect runs its block with the lock held, so updates don't interleave.

not in browser
my $lock = Lock.new;
my @log;
await (^3).map(-> $i { start { $lock.protect({ @log.push($i) }) } });
say @log.sort;
Output
(0 1 2)

Channels #

A Channel is a thread-safe queue: one thread .sends, another reads. Closing it ends the .list.

not in browser
my $c = Channel.new;
start { $c.send($_) for 1..3; $c.close }
say $c.list.sort;
Output
(1 2 3)

Notes #