关于Raku语言及Rakudo底层延续特性的技术问询
Great question! Let's unpack this thoroughly, covering both the Raku language specification and its primary implementation, Rakudo.
Raku Language-Level Continuations
First, it's important to clarify: the Raku language itself does not expose continuations directly to end users. From a developer writing Raku code, you won't find built-in syntax or APIs for creating/manipulating continuations—so the short answer for Raku the language is indeed "no exposed continuations". That said, Rakudo (the de facto Raku implementation) relies on underlying continuation support to power several core language features.
Rakudo's Underlying Continuation Features
Let's go through each of the six properties you outlined:
- Asymmetric vs Symmetric: Rakudo's continuations are asymmetric. When a continuation is suspended or yields, execution returns directly to the caller that invoked
Continuation.run(). While symmetric continuations can be simulated using asymmetric ones, Rakudo's native implementation is asymmetric, aligning with the behavior you described. - Stackful vs Stackless: Rakudo uses stackful continuations. These can suspend execution at any depth of the call stack, not just within the starting subroutine of a limited context (unlike stackless continuations like those in C#). This means they maintain a full independent call stack rather than a single subroutine frame, giving them greater expressive power.
- Delimited vs Undelimited: Rakudo's continuations are delimited. They capture the execution context starting from a specific invocation boundary (like the body of a runnable) rather than the entire execution state up to
main(). This makes them practically useful, unlike undelimited continuations which are generally considered too broad for real-world use. - Multi-prompt: Rakudo supports multi-prompt continuations. You can suspend an outer continuation from any point in the call stack, similar to nested
try/catchblocks—where throwing a specific exception unwinds to the nearest matchingcatch. For example, blocking I/O in Python-style generators (or Raku's async constructs) can suspend the outer thread continuation precisely by targeting the appropriate prompt. - One-shot/Non-reentrant vs Reentrant: Rakudo's continuations are one-shot/non-reentrant by default. Resuming a suspended continuation modifies its internal state, so you can't resume from the same suspension point multiple times. Reentrant behavior (where each suspension returns a new immutable continuation representing that point) isn't native, but can be achieved via cloning.
- Cloneable: Yes, Rakudo's continuations are cloneable. By cloning a one-shot continuation before resuming it, you create a snapshot of its state at the suspension point. This lets you resume from that snapshot later, effectively replicating the capabilities of a reentrant continuation.
Raku Features That Depend on Continuations
Several core Raku features are built on top of Rakudo's underlying continuation support:
- Async & Coroutines: The
startkeyword,awaitmechanism, and Raku's entire asynchronous programming model rely on continuations to suspend and resume execution of async tasks. - Generators & Lazy Lists: Constructs like
gather/takeand lazy lists use continuations to pause iterator execution when a value is yielded (take), then resume when the next value is requested. - Exception Handling: While
try/catchis exposed as language syntax, the underlying mechanism that unwinds the call stack to find a matching handler uses continuations under the hood. - Virtual Threads: Raku's lightweight virtual threads leverage continuations to handle scheduling—suspending a thread when it blocks (e.g., on I/O) and resuming it later without the overhead of OS thread context switches.
Acknowledgments
Huge thanks to @Larry, Stefan O'Rear, and jnthn for their pivotal work on continuations in the Raku ecosystem. Their contributions laid the groundwork for these powerful control flow capabilities.
内容的提问来源于stack exchange,提问作者raiph

