ticked_async_executor 0.4.0

Local executor that runs woken async tasks when it is ticked
Documentation

Ticked Async Executor

Async Local Executor which executes woken tasks only when it is ticked

Usage

Default Local Executor

use ticked_async_executor::*;

const DELTA: f64 = 1000.0 / 60.0;

let mut executor = TickedAsyncExecutor::default();

executor.spawn_local("MyIdentifier", async move {}).detach();

// Tick your executor to run the tasks
assert_eq!(executor.num_tasks(), 1);
executor.tick(DELTA, None);
assert_eq!(executor.num_tasks(), 0);

Split Local Executor

use ticked_async_executor::*;

const DELTA: f64 = 1000.0 / 60.0;

let (spawner, mut ticker) = SplitTickedAsyncExecutor::default();

spawner.spawn_local("MyIdentifier", async move {}).detach();

// Tick your ticker to run the tasks
assert_eq!(spawner.num_tasks(), 1);
ticker.tick(DELTA, None);
assert_eq!(spawner.num_tasks(), 0);

// spawner can be cloned
let spawner_clone = spawner.clone();

Limit the number of woken tasks run per tick

use ticked_async_executor::*;

const DELTA: f64 = 1000.0 / 60.0;

let mut executor = TickedAsyncExecutor::default();

executor.spawn_local("MyIdentifier1", async move {}).detach();
executor.spawn_local("MyIdentifier2", async move {}).detach();

// Runs upto 1 woken tasks per tick
assert_eq!(executor.num_tasks(), 2);
executor.tick(DELTA, Some(1));
assert_eq!(executor.num_tasks(), 1);
executor.tick(DELTA, Some(1));
assert_eq!(executor.num_tasks(), 0);

Features

  • tick_event
  • timer_registration

Tick Registration

#[cfg(feature = "timer_registration")]
{
  use ticked_async_executor::*;

  const DELTA: f64 = 1000.0 / 60.0;

  let mut executor = TickedAsyncExecutor::default();

  // These APIs are gated under the `timer_registration` feature
  let timer = executor.create_timer_from_timer_registration();

  executor.spawn_local("MyIdentifier1", async move {
    timer.sleep_for(10.0).await;
  }).detach();
  
  executor.wait_till_completed(1.0);
  assert_eq!(executor.num_tasks(), 0);
}

Tick Event

#[cfg(feature = "tick_event")]
{
  use ticked_async_executor::*;

  const DELTA: f64 = 1000.0 / 60.0;

  let mut executor = TickedAsyncExecutor::default();

  // These APIs are gated under the `tick_event` feature
  let _delta_tick_rx = executor.tick_channel();
  let timer = executor.create_timer_from_tick_event();

  executor.spawn_local("MyIdentifier1", async move {
    timer.sleep_for(10.0).await;
  }).detach();

  executor.wait_till_completed(1.0);
  assert_eq!(executor.num_tasks(), 0);
}

Benchmarks

  • executor.spawn_local
Spawn 10000 tasks
time:   [1.3711 ms 1.3713 ms 1.3715 ms]
  • executor.create_timer_from_timer_registration under feature timer_registration
Spawn 1000 timers from timer registration
time:   [336.10 µs 336.42 µs 336.93 µs]
  • executor.create_timer_from_tick_event under feature tick_event
Spawn 1000 timers from tick event
time:   [1.5688 ms 1.5692 ms 1.5697 ms]

Caveats

  • Uses the smol ecosystem
  • Ensure that tasks are spawned on the same thread as the one that initializes the executor

Roadmap

  • TickedAsyncExecutor
  • SplitTickedAsyncExecutor
    • Similar to the channel API
    • Spawner is !Send + Clone
    • Ticker is !Send + !Clone
  • Timers
    • Notification based: TickedTimerFromTimerRegistration
    • Polling based: TickedTimerFromTickEvent