David Alsh
David Alsh

Reputation: 7675

How to manually poll Runtime to drive futures without blocking current thread?

I am trying to implement a non-blocking current-threaded executor on top of Tokio that I can integrate into another single threaded event-loop.

For this reason I cannot use runtime.block_on() as I cannot block the main thread.

I'm trying this but poll_fn never runs

fn main() {
  let runtime = Builder::new_current_thread().enable_all().build().unwrap();

  let mut handle = runtime.spawn(async {
    println!("1");
    tokio::time::sleep(Duration::from_secs(1)).await;
    println!("2");
  });

  // Pretend this is an external event loop
  for _ in 0..1000 {
    poll::poll_fn(|ctx| {
      Future::poll(Pin::new(&mut handle), ctx)
    });
  }
}

I was able to achieve something similar with smol, however I want to use tokio to have access to its utilities.

fn main() {
  let ex = smol::LocalExecutor::new();

  ex.spawn(async {
    println!("1");
    tokio::time::sleep(Duration::from_secs(1)).await;
    println!("2");
  }).detach();

  // external event loop
  loop { 
    ex.try_tick();
    if ex.is_empty() {
      break;
    }
  }
}

Upvotes: 1

Views: 289

Answers (1)

Adesoji Alu
Adesoji Alu

Reputation: 313

this is what i did,you need to take into consideration the LocalSet which is used to run localized tasks that are not bound across threads and this is my code below

use tokio::runtime::Builder;
use tokio::task::LocalSet;
use std::time::Duration;
use tokio::time::sleep;



fn main() {
    // first, you need to create a runtime and local task set for executing futures.
    let rt = Builder::new_current_thread().enable_all().build().unwrap();
    let local_set = LocalSet::new();

    //now, you spawn a non-blocking task
    local_set.spawn_local(async {
        println!("1");
        sleep(Duration::from_secs(1)).await;
        println!("2");
    });

    // after, we simulate an external event loop and manually run the runtime
    local_set.block_on(&rt, async {
        let mut interval = tokio::time::interval(Duration::from_millis(100));
        loop {
            //therefore, we poll all tasks in the LocalSet
            interval.tick().await;
            //  then we Check if tasks are still running again or exit if done
            // but i will say that in a real scenario, more complex logic might be defined for you to know when to exit
        }
    });
}

this is my cargo.toml below

[package]
name = "my_tauri_test"
version = "0.1.0"
edition = "2024"
Author = "Adesoji Au"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tokio = { version = "1", features = ["full"] }
futures = "0.3"

Upvotes: 0

Related Questions