Coroutine

public final class Coroutine

Lightweight coroutine.

Launching coroutines and switching between them is extremely fast. It requires only a few machine instructions. This makes coroutines a suitable basic flow control mechanism, like the if or while keywords, which have comparable performance.

Coroutines have one big limitation, though: All coroutines run on a single CPU core. If you want to take advantage of multiple cores, you have to launch multiple threads or processes, presumably as many of them as there are CPU cores on your machine.

Coroutines are scheduled cooperatively. What that means is that a coroutine has to explicitly yield control of the CPU to allow a different coroutine to run. In a typical scenario, this is done transparently to the user: When a coroutine invokes a function that would block (such as Coroutine.wakeUp, FileDescriptor.poll, channel.send or channel.receive), the CPU is automatically yielded. However, if a coroutine runs without calling any blocking functions, it may hold the CPU forever. For these cases, the Coroutine.yield function can be used to manually relinquish the CPU to other coroutines manually.

Example:

let coroutine = try Coroutine {
    ...
}

coroutine.cancel()
  • Launches a coroutine that executes the closure passed as argument. The coroutine is executed concurrently, and its lifetime may exceed the lifetime of the caller.

    Example:

    let coroutine = try Coroutine {
        ...
    }
    
    coroutine.cancel()
    

    Throws

    The following errors might be thrown:

    VeniceError.canceledCoroutine

    Thrown when the operation is performed within a canceled coroutine.

    VeniceError.outOfMemory

    Thrown when the system doesn’t have enough memory to create a new coroutine.

    Declaration

    Swift

    public init(body: @escaping () throws -> Void) throws

    Parameters

    body

    Body of the newly created coroutine.

  • Cancels the coroutine.

    Warning

    Once a coroutine is canceled any coroutine-blocking operation within the coroutine will throw VeniceError.canceledCoroutine.

    Declaration

    Swift

    public func cancel()
  • Explicitly passes control to other coroutines. By calling this function, you give other coroutines a chance to run.

    You should consider using Coroutiner.yield() when doing lengthy computations which don’t have natural coroutine switching points.

    Example:

    for _ in 0 ..< 1000000 {
        expensiveComputation()
        try Coroutine.yield() // Give other coroutines a chance to run.
    }
    

    Warning

    Once a coroutine is canceled calling Couroutine.yield will throw VeniceError.canceledCoroutine.

    Throws

    The following errors might be thrown:

    VeniceError.canceledCoroutine

    Thrown when the operation is performed within a canceled coroutine.

    Declaration

    Swift

    public static func yield() throws
  • Wakes up at deadline.

    Example:

    func execute<R>(_ deadline: Deadline, body: (Void) throws -> R) throws -> R {
        try Coroutine.wakeUp(deadline)
        try body()
    }
    
    try execute(1.second.fromNow()) {
        print("Hey! Ho! Let's go!")
    }
    

    Warning

    Once a coroutine is canceled calling Couroutine.wakeUp will throw VeniceError.canceledCoroutine.

    Throws

    The following errors might be thrown:

    VeniceError.canceledCoroutine

    Thrown when the operation is performed within a canceled coroutine.

    Declaration

    Swift

    public static func wakeUp(_ deadline: Deadline) throws
  • Coroutine groups are useful for canceling multiple coroutines at the same time.

    Example:

    let group = Coroutine.Group(minimumCapacity: 2)
    
    try group.addCoroutine {
        ...
    }
    
    try group.addCoroutine {
        ...
    }
    
    // all coroutines in the group will be canceled
    group.cancel()
    
    See more

    Declaration

    Swift

    public class Group