Async with tokio
Regular functions block threads
Async doesn’t block threads
Before we look at what tokio does, let’s consider how we’d run 3 tasks if they were ‘blocking’
Without Tokio (blocking):
If you used std::thread::sleep
, the execution would pause (block) for each function call until the sleep duration completes. This means that when you execute the code sequentially, the first do_stuff
would block the execution for its sleep time, followed by the second, and then the third. The tasks would not run concurrently.
With Tokio (non-blocking):
Using tokio::time::sleep
with async/await
, the program can yield control while sleeping. This allows other tasks to proceed during the sleep period without blocking the thread. When you use join!
, all three do_stuff
functions can run concurrently without blocking the thread, making them execute in parallel (asynchronously).
In summary, with Tokio, the code becomes asynchronous, allowing concurrent execution, while without Tokio or an asynchronous runtime, the execution would be blocking and sequential.
Make the thread sleep WITHOUT tokio::time::sleep
use std::thread;
use tokio::*;
use rand::{thread_rng, Rng};
async fn do_stuff(nm:i32){
let rn = thread_rng().gen_range(1..100);
thread::sleep(std::time::Duration::from_millis(rn));
//tokio::time::sleep(std::time::Duration::from_millis(rn)).await;
println!("{:?}",nm );
}
#[tokio::main]
async fn main() {
join!(do_stuff(1), do_stuff(2), do_stuff(3));
}
1
2
3
[Process exited 0]
//use std::thread;
use tokio::*;
use rand::{thread_rng, Rng};
async fn do_stuff(nm:i32){
let rn = thread_rng().gen_range(1..100);
//thread::sleep(std::time::Duration::from_millis(rn));
tokio::time::sleep(std::time::Duration::from_millis(rn)).await;
println!("{:?}",nm );
}
#[tokio::main]
async fn main() {
join!(do_stuff(1), do_stuff(2), do_stuff(3));
}
3
2
1
[Process exited 0]
try_join
use tokio::*;
use rand::{thread_rng,Rng};
async fn do_stuff(nm:i32)-> Result<(), Box<dyn std::error::Error>>{
let rn = thread_rng().gen_range(1..100);
tokio::time::sleep(std::time::Duration::from_millis(rn)).await;
println!("{:?}",nm );
// Simulate a failure for nm == 2
if nm % 2 ==0 {
return Err(format!("Future {} failed!", nm).into());
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = tokio::try_join!(do_stuff(1), do_stuff(2), do_stuff(3));
match res {
Ok(_)=>{println!("{:?}", "All futures suceeded")},
Err(e)=>{println!("Errrr{}",e)}
}
Ok(())
}