Macro anony::join_cyclic

source ·
join_cyclic!() { /* proc-macro */ }
Available on crate feature future only.
Expand description

Returns a future that “joins” multiple futures that will be completed concurrently, using cycling polling strategy.

Usage note: If you are not sure which one to use (between this macro with join!), just use the latter.

It’s output is a tuple of input futures’ outputs.

It is more efficient than awaiting futures like this: (fut1.await, fut2.await, fut3.await), since these futures will be resolved sequencially (fut1 must be done first before awaiting fut2, and fut3). join!(fut1, fut2, fut3).await will poll every futures on getting polled, which makes them concurrently awaited.

This future will cycle the first future to be polled for each time it is polled, which is similar to the tokio’s one. For example, join!(fut1, fut2, fut3) polls fut1 first for the first time being polled, then it polls ‘fut2’ for the second time, then fut3 will be the first, then it rolls back to fut1, and so on. This strategy ensure fairness as it reduces the chance that heavy futures may make other futures stuck. If fairness is not your concern, consider using join!, which is less fairer but more efficient.

§Possible differences from other implementations

  • join_cyclic! returns an instance of an anonymous type implemented Future instead of requiring it to be inside an async. You will be warned if you neither .await, poll, nor return it.

  • input futures are required to implement IntoFuture.

  • the returned future (generally) has smaller size and is (generally) faster.

  • the returned future is Unpin if all of the input futures are Unpin.

§Examples

use anony::join_cyclic;

let a = async { 1 };
let b = async { 2 };
let c = async { 3 };
assert_eq!(join_cyclic!(a, b, c).await, (1, 2, 3));

If you want to run a future (or more) while doing something else, this macro is a help! Note that you must put the “something else” after every other futures you want to run:

use anony::join_cyclic;
use tokio::time::sleep;
use std::time::Duration;

async fn read_db() -> String {
    sleep(Duration::from_secs(1)).await;
    "My secret".into()
}

let (secret_value, _) = join_cyclic!(read_db(), async {
    // Your other tasks go here, maybe asynchronous or just blocking...
    let a = 1;
    let b = 2;
    assert_eq!(a + b, 3);
}).await;

assert_eq!(secret_value, "My secret");