Recently I was playing with C++ coroutines. Boost::asio
has interface that works pretty good with co_await
for networking but using boost::asio
is painful. So I want something like this in Rust.
I want time-sliced IO. Imagine a game where I run every step of the pipeline (input, physics, scripts, rendering) and with all the time I have left I run IO handling.
I want to use tokio::task::LocalSet
to simulate this behaviour. I'd local.run_until
with a future made from time::sleep()
to define how big the time-slice is (might vary every frame). I'd spawn two tasks, one for handling input and the other one for output.
First question - does it even makes sense to use tokio
like this?
Second question - performance... I expect tokio
is super smart but I want to make sure - if there are 2 tasks hanged on IO (no data is coming) and 1 task that was just spawned for timing run_until(time::sleep(50ms))
tokio is going to sleep right? I expect that time-slice to be pretty large, most likely larger than time required to process everything. So I hope thread will sleep and won't be scheduled for the entire duration unless something really comes on the IO.
Here's some code that I tested this on:
use tokio::{task, time};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let local = task::LocalSet::new();
local.spawn_local(async move {
loop {
time::sleep(time::Duration::from_millis(10)).await;
println!("Task 1. working! Doing some crazy IO.");
}
});
local.spawn_local(async move {
loop {
time::sleep(time::Duration::from_millis(20)).await;
println!("Task 2. working! Doing even crazier IO!");
}
});
local.run_until(async move {
time::sleep(time::Duration::from_millis(50)).await;
}).await;
println!("Break!");
println!("Do other things, we don't care about IO!");
local.run_until(time::sleep(time::Duration::from_millis(50))).await;
println!("Finish");
}