In this video I explain how to use async functions, a bit how they work and how to use a runtime from the tokio crate.
We are using the futures
crate:
[dependencies]
futures = { version = "0.3.30", features = ["thread-pool"] }
And here is our first program:
use futures::executor::block_on;
async fn f(a: i64, b:i64) -> i64 {
println!("Hello f");
a+b
}
fn main() {
let fut = f(1, 2);
println!("Hello");
let x = block_on(fut);
println!("Done: {}", x);
}
As we see, futures are only executed if there is a runtime which polls them.
In an async function, the .await
method is a suspension point, the
compiler generates a state machine for us.
use futures::executor::block_on;
async fn g(c: i64) -> i64 {
println!("Hello g {}", c);
c*c
}
async fn f(a: i64, b:i64) -> i64 {
println!("Hello f");
let aa = g(a).await;
println!("Hello f2");
let bb = g(b).await;
println!("Hello f3");
aa+bb
}
fn main() {
let fut = f(1, 2);
println!("Hello");
let x = block_on(fut);
println!("Done: {}", x);
}
use futures::executor::ThreadPool;
async fn g(c: i64) -> i64 {
println!("Hello g {}", c);
std::thread::sleep(std::time::Duration::from_secs(1));
println!("Done g {}", c);
c*c
}
async fn f(a: i64, b:i64) {
println!("Hello f");
let aa = g(a);
let bb = g(b);
println!("Hello f2");
let x = futures::join!(aa, bb);
println!("Hello f3: {}", x.0 + x.1);
}
fn main() {
let fut1 = f(1, 2);
let fut2 = f(3, 4);
println!("Hello");
let pool = ThreadPool::builder().pool_size(4).create().unwrap();
pool.spawn_ok(fut1);
pool.spawn_ok(fut2);
std::thread::sleep(std::time::Duration::from_secs(10));
println!("Done");
}
Here we see that two async functions run concurrently.
Here we use this dependency:
[dependencies]
tokio = { version = "1.36.0", features = ["full"] }
async fn g(c: i64) -> i64 {
println!("Hello g {}", c);
std::thread::sleep(std::time::Duration::from_secs(c as u64));
c*c
}
async fn f(a: i64, b:i64) -> i64 {
println!("Hello f");
let aa = g(a).await;
println!("Hello f2");
let bb = g(b).await;
println!("Hello f3");
aa+bb
}
#[tokio::main]
async fn main() {
println!("Hello");
let fut = f(1, 2);
let fut2 = f(3, 4);
println!("Hello2");
let x = fut.await;
println!("Hello3");
let y = fut2.await;
println!("Done: {} {}", x, y);
}
async fn g(c: i64) -> i64 {
println!("Hello g {}", c);
std::thread::sleep(std::time::Duration::from_secs(c as u64));
c*c
}
async fn f(a: i64, b:i64) -> i64 {
println!("Hello f");
let aa = g(a).await;
println!("Hello f2");
let bb = g(b).await;
println!("Hello f3");
aa+bb
}
#[tokio::main]
async fn main() {
println!("Hello");
let handle = tokio::spawn(f(1, 2));
let handle2 = tokio::spawn(f(3, 4));
println!("Hello2");
let x = handle.await.unwrap();
println!("Hello3");
let y = handle2.await.unwrap();
println!("Done: {} {}", x, y);
}
async fn g(c: i64) -> i64 {
println!("Hello g {}", c);
std::thread::sleep(std::time::Duration::from_secs(c as u64));
c*c
}
async fn f(a: i64, b:i64) -> i64 {
println!("Hello f");
let aa = g(a).await;
println!("Hello f2");
let bb = g(b).await;
println!("Hello f3");
aa+bb
}
fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
println!("Hello");
let handle = tokio::spawn(f(1, 2));
let handle2 = tokio::spawn(f(3, 4));
println!("Hello2");
let x = handle.await.unwrap();
println!("Hello3");
let y = handle2.await.unwrap();
println!("Done: {} {}", x, y);
});
}
- Async rust getting started: https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html
- Async/await primer: https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html
- The future trait: https://rust-lang.github.io/async-book/02_execution/02_future.html
- Tokio tutorial: https://tokio.rs/tokio/tutorial
- Tokio reference: https://docs.rs/tokio/latest/tokio/index.html
- Video: https://youtu.be/rmeGVQW3Rjo
- Overview: https://gist.github.com/max-itzpapalotl/18f7675a60f6f9603250367bcb63992e