Tokio 运行时
学习目标
- 理解 Tokio 运行时
- 掌握常用 API
- 理解多线程 vs 当前线程运行时
核心概念
基本用法
#[tokio::main]
async fn main() {
println!("Hello from Tokio!");
}
fn main() {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(async {
println!("Hello from Tokio!");
})
}
常用 API
use tokio::time::{sleep, Duration, timeout};
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
sleep(Duration::from_secs(1)).await;
"done"
});
match timeout(Duration::from_millis(500), handle).await {
Ok(result) => println!("完成: {:?}", result),
Err(_) => println!("超时"),
}
tokio::select! {
_ = sleep(Duration::from_secs(1)) => println!("sleep 完成"),
_ = sleep(Duration::from_secs(2)) => println!("这个不会执行"),
}
}
运行时配置
#[tokio::main(flavor = "current_thread")]
async fn main() {
}
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() {
}
IO 操作
use tokio::fs;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = fs::read_to_string("data.txt").await?;
println!("{}", content);
fs::write("output.txt", "hello").await?;
let listener = tokio::net::TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (socket, addr) = listener.accept().await?;
tokio::spawn(async move {
});
}
}
实践练习
练习 1:并发 URL 抓取
use tokio::time::{sleep, Duration};
async fn fetch_url(url: &str) -> String {
sleep(Duration::from_millis(100)).await;
format!("Response from {}", url)
}
#[tokio::main]
async fn main() {
let urls = vec!["http://a.com", "http://b.com", "http://c.com"];
let mut handles = vec![];
for url in urls {
handles.push(tokio::spawn(fetch_url(url).to_string()));
}
for handle in handles {
println!("{}", handle.await.unwrap());
}
}
小结
| API | 用途 |
|---|
#[tokio::main] | 异步 main |
tokio::spawn | 并发任务 |
tokio::select! | 选择最快完成的 |
tokio::time::sleep | 异步休眠 |
tokio::fs | 异步文件操作 |
tokio::net | 异步网络 |