What is the difference between asymmetric and symmetric coroutines?

Coroutines switch between caller and callee, e.g. you enter the coroutine-function and you switch back to the calling code. Usually (asymmetric) coroutines have two functions for this purpose:

  • a resume-function that is called by the caller
  • a suspend-function that is called from within the coroutine

Because you have two functions to switch the context, it is called asymmetric. Symmetric coroutines have only one function that suspends the current context and resumes another one. Note that you have to specify which symmetric coroutine has to be resumed next.

Symmetric coroutines can be used to implement user-land threads (a symmetric coroutine represents a userland thread; the scheduler jumps from one coroutine to the next symmetric coroutine, e.g. the next user-land thread is scheduled) more efficiently than asymmetric coroutines. This is obvious because symmetric coroutines do not need to jump back to the caller in order to resume the next user-land thread. Asymmetric coroutines need more context switches than symmetric coroutines in order to achive the same functionality.

Symmetric coroutines - symmetric context switching - is better represented by concepts like 'call with current continuation' (Scheme, Ruby ...). boost.context supports this concept with its implementation of callcc()/continuation. Therefore boost.coroutine2 does not provide a symmetric coroutine API - but the asymmetric coroutine of boost.coroutine2 is implemented with boost.context's callcc()/continuation.


The difference between symmetric and asymmetric coroutines is described particularly well by Ana Lúcia de Moura and Roberto Ierusalimschy in their paper "Revisiting Coroutines":

A well-known classification of coroutines concerns the control-transfer operations that are provided and distinguishes the concepts of symmetric and asymmetric coroutines. Symmetric coroutine facilities provide a single control-transfer operation that allows coroutines to explicitly pass control between themselves. Asymmetric coroutine mechanisms (more commonly denoted as semi-symmetric or semi coroutines) provide two control-transfer operations: one for invoking a coroutine and one for suspending it, the latter returning control to the coroutine invoker. While symmetric coroutines operate at the same hierarchical level, an asymmetric coroutine can be regarded as subordinate to its caller, the relationship between them being somewhat similar to that between a called and a calling routine.

Coroutine mechanisms to support concurrent programming usually provide symmetric coroutines to represent independent units of execution, like in Modula-2. On the other hand, coroutine mechanisms intended for implementing constructs that produce sequences of values typically provide asymmetric coroutines. Examples of this type of construct are iterators and generators.

(Citations omitted)

In the asymmetric coroutine model, "asymmetry" refers to the fact that there is a stack-like caller–callee relationship between coroutines. A coroutine can either call another coroutine or suspend itself by yielding control to its caller, typically also yielding a value to the caller at the same time.

In the symmetric coroutine model, a coroutine may yield control to any other coroutine without restriction.

The two models actually have the same expressive power; i.e. asymmetric coroutines can be implemented using symmetric coroutines and vice versa. (See Symmetric coroutines, written by Giovanni P. Deretta, for a transformation between the two types of coroutines.) Consequently, Moura and Ierusalimschy write: "Providing both constructs only complicates the semantics of the [coroutine] mechanism, with no increase in its expressive power."

The developers of Coroutine2 decided not to provide symmetric coroutines in the library because they believe that symmetric coroutine functionality is better implemented by boost::context::execution_context (part of Boost.Context): http://lists.boost.org/Archives/boost/2015/06/223701.php

Tags:

Coroutine