快速开始
并发编程初体验
- 同时请求两个网页, 提取网页的 title
- 哪个网页先提取完成就先输出哪个网页的 title
- 实现异步发送请求并解析提取html文档的 tilte
rust
use trpl::{self, Either, Html};
fn main() {
let urls: Vec<String> = vec![
String::from("https://rust-lang.org/"),
String::from("https://www.baidu.com/"),
];
// 绑定异步运行时, 所有异步代码都用这个 trpl::run 函数来执行
trpl::run(async {
let fut1 = get_page_title(&urls[0]);
let fut2 = get_page_title(&urls[0]);
// trpl::race: 对比两个 future 哪个先完成就会匹配到哪个
let title = match trpl::race(fut1, fut2).await {
Either::Left(title) => title,
Either::Right(title) => title,
};
// 可能是百度, 也可能是 rust-lang.org
println!("title: {}", title.unwrap());
});
}
// async/await 语法
async fn get_page_title(url: &str) -> Option<String> {
let response = trpl::get(url).await;
let body = response.text().await;
Html::parse(&body)
.select_first("title")
.map(|title_el| title_el.inner_html().trim().to_string())
}rust
// 手动返回 Future 实现
// async/await 语法只是语法糖, 最终编译器还是会将代码变为这个样子
fn get_page_title(url: &str) -> impl std::future::Future<Output = Option<String>> + '_ {
async move {
let response = trpl::get(url).await;
let body = response.text().await;
Html::parse(&body)
.select_first("title")
.map(|title_el| title_el.inner_html().trim().to_string())
}
}顺序执行 vs 并发执行
rust
use std::time::Instant;
use trpl::{self, Html};
// 异步发送请求并解析提取html文档的title
async fn get_page_title(url: &str) -> Option<String> {
let response = trpl::get(url).await;
let body = response.text().await;
Html::parse(&body)
.select_first("title")
.map(|title_el| title_el.inner_html().trim().to_string())
}
fn main() {
let urls: Vec<String> = vec![
String::from("https://rust-lang.org/"),
String::from("https://play.rust-lang.org"),
String::from("https://doc.rust-lang.org/std/index.html"),
String::from("https://doc.rust-lang.org/book"),
String::from("https://doc.rust-lang.org/cargo/index.html"),
String::from("https://doc.rust-lang.org/rustdoc/index.html"),
String::from("https://doc.rust-lang.org/rustc/index.html"),
String::from("https://rust-cli.github.io/book/index.html"),
String::from("https://doc.rust-lang.org/error_codes/error-index.html"),
];
// 顺序执行
trpl::run(async {
println!("=== 顺序执行 ===");
let start = Instant::now();
for url in urls.iter() {
let title = get_page_title(url).await;
println!("title: {}", title.unwrap());
}
println!("顺序执行总耗时: {:?}", start.elapsed());
});
// 并发执行
trpl::run(async {
println!("=== 并发执行 ===");
let start = Instant::now();
let futures: Vec<_> = urls.iter().map(|url| get_page_title(url)).collect();
let titles = trpl::join_all(futures).await;
for title in titles {
println!("title: {}", title.unwrap());
}
println!("并发执行总耗时: {:?}", start.elapsed());
});
}性能影响关键
- 顺序执行: 请求1 → 等待完成 → 请求2 → 等待完成 -> ...(总耗时 = 9个请求耗时之和)
- 并发执行: 请求1-9 同时发起(总耗时 ≈ 最慢的那个请求的耗时)
[注意]
- 使用 trpl::join 或 trpl::join_all 才能让异步代码
真正并发执行 - 否则即使写了 async/await, 如果只是按顺序
.await仍然是顺序执行的
trpl 介绍
trpl 是 rust 的官方文档, 它是一个全面的 rust 学习教程, 每个章节都有对应的代码, 可以在线运行, 也可以下载到本地运行