Skip to main content

Module co

Module co 

Source
Available on crate feature coroutine only.
Expand description

§Coroutines (Async)

cu is designed to have flexible coroutine handling. For example, consider these program styles:

  • everything being async - typically involving both CPU-bound work and IO work interwined. Can take advantage of multiple background threads.
  • Some IO heavy work that doesn’t really involve CPU - for example, spawning compiler processes and wait for them, or spawning network requests. Usually won’t have significant performance benefit from having multiple background threads.
  • Heavy CPU work that only has a little IO. Using async usually has very little benefit. (Would probably use something like rayon to get parallelism).

You pick the style you want.

The async runtime being used under the hood is tokio. There are 2 feature flags you can choose from: coroutine and coroutine-heavy. coroutine uses one foreground (current-thread) tokio runtime and one background thread to drive IO tasks. coroutine-heavy does not have a current-thread runtime - everything is done on the multi-threaded, background runtime.

§Async entry point

To make your entire program async with cli, simply make the main function `async.

use std::time::Duration;
#[cu::cli]
async fn main(_: cu::cli::Flags) -> cu::Result<()> {
    cu::info!("doing some work");
    tokio::time::sleep(Duration::from_millis(100)).await;
    cu::info!("done");
    Ok(())
}

When using coroutine, the main future will be spawned onto the current-thread runtime (so the main thread is still driving it). When using coroutine-heavy, the main future is spawned onto the background runtime, and the main thread waits until the future is completed.

§Coroutines used internally and co_* APIs

Some cu functions use coroutines internally behind “synchronous” APIs, allowing seamless integration from a synchronous context.

For example, when spawning child processes, an async task processes IO from the child and streams results to the main thread. This allows for a clean API to for example, read child’s output line-by-line.

However, there is an important catch - it is crucial that we never block an async runtime. This means to wait for a future:

  • If we are not in an async runtime, we can enter the async runtime by calling an entry point to the runtime (a.k.a block), to block the current thread while letting the runtime run until the future is finished.
  • If we are already in an async runtime, we must call .await instead of block. Otherwise, either the entire runtime will block and may deadlock, or tokio will detect it and panic.

This is why the APIs that use coroutine under the hood will have another version with a co_* prefix. For example, spawn and co_spawn. You MUST use .spawn()? if not in an async runtime, and .co_spawn().await? in an async runtime. Note that calling .co_spawn() while not in an async runtime is also not allowed, because tokio will assume a runtime is active and panic if not.

§Advanced Usage

If additional functionality from tokio is needed (not already provided by re-exports), then you can add tokio to Cargo.toml:

[dependencies]
tokio = "1"

Macros§

join
Waits on multiple concurrent branches, returning when all branches complete.
select
Waits on multiple concurrent branches, returning when the first branch completes, cancelling the remaining branches.
try_join
Waits on multiple concurrent branches, returning when all branches complete with Ok(_) or on the first Err(_).

Structs§

Handle
Join handle for async task
Pool
A pool for limiting async tasks
RobustAbortHandle
RobustHandle
Join handle for async task, like Handle, with a more robust mechanism for aborting.
Set
A set of Handles that can be joined concurrently.

Functions§

pool
Create a new Pool.
run
Run an async task using the background runtime
set
Create a set of handles, that can be joined concurrently.
set_flatten
Create a set of handles, that can be joined concurrently.
sleep
Waits until duration has elapsed.
spawn
Spawn a task onto the background runtime
spawn_blockingcoroutine-heavy
Spawn a task onto the blocking pool of the background runtime

Type Aliases§

AbortHandle