Pop Quiz: Shrink that `Future`
Here's a small example of an async
function in Rust.
async fn data() -> u8 {
0
}
async fn test() {
println!("{}", data().await);
}
fn main() {
dbg!(std::mem::size_of_val(&test()));
}
Let's run this program and see how big the test()
future is.
[src/main.rs:10:5] std::mem::size_of_val(&test()) = 24
Here's the quiz: can we make the Future
returned by test()
smaller? I'll
give you a moment to think about it.
Answer
How is the `Future` the compiler is constructing for us laid out? We can use `gdb` to print out the type `rustc` is generating for us.(gdb) ptype test()
type = enum shrink_future::test::{async_fn_env#0} {
0,
1,
2,
3{__0: &[&str], __awaitee: shrink_future::data::{async_fn_env#0}},
}
Since our test()
future has one .await
point, we need to store the future
we're waiting on as well as any data used across the .await
point. The
println!
macro is setting up a &[&str]
for us which is accessed on both
sides of the .await
. This is unnecessary; if we .await
the data()
future
first, and store it in a local variable before doing println!
, then we'll only
have to store the future we're waiting on.
async fn test() {
let data = data().await;
println!("{}", data);
}
Let's run our program again.
[src/main.rs:11:5] std::mem::size_of_val(&test()) = 2
Much better!