async/await 基础
学习目标
- 理解异步编程模型
- 掌握
async fn 和 .await
- 理解 Future 的概念
核心概念
async fn
async fn greet() -> String {
String::from("hello")
}
fn greet() -> impl std::future::Future<Output = String> {
async { String::from("hello") }
}
.await
async fn fetch_data() -> String {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
String::from("data")
}
#[tokio::main]
async fn main() {
let data = fetch_data().await;
println!("{}", data);
}
Future trait
trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
enum Poll<T> {
Ready(T),
Pending,
}
并发执行
use tokio::time::{sleep, Duration};
async fn task(id: u32) -> String {
sleep(Duration::from_millis(100)).await;
format!("任务 {} 完成", id)
}
#[tokio::main]
async fn main() {
let r1 = task(1).await;
let r2 = task(2).await;
let (r1, r2) = tokio::join!(task(1), task(2));
let mut handles = vec![];
for i in 0..5 {
handles.push(tokio::spawn(task(i)));
}
for handle in handles {
let result = handle.await.unwrap();
println!("{}", result);
}
}
async 块
#[tokio::main]
async fn main() {
let future = async {
println!("执行中...");
42
};
let result = future.await;
println!("结果: {}", result);
}
tokio::spawn
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
"result"
});
let result = handle.await.unwrap();
println!("{}", result);
}
实践练习
练习 1:并发请求
use tokio::time::{sleep, Duration};
async fn fetch_user(id: u32) -> String {
sleep(Duration::from_millis(100)).await;
format!("User-{}", id)
}
#[tokio::main]
async fn main() {
let users: Vec<String> = (1..=5)
.map(|id| fetch_user(id))
.collect::<Vec<_>>()
.await
.into_iter()
.collect();
println!("{:?}", users);
}
常见错误
1. 忘记 .await
async fn foo() -> i32 { 42 }
#[tokio::main]
async fn main() {
let f = foo();
let v = foo().await;
}
2. 在同步代码中使用 async
#[tokio::main]
async fn main() {
foo().await;
}
小结
| 概念 | 说明 |
|---|
async fn | 异步函数,返回 Future |
.await | 等待 Future 完成 |
tokio::spawn | 并发执行任务 |
tokio::join! | 并发等待多个 Future |
Future | 惰性计算,需要执行器驱动 |