异步Rust中的多线程-为什么我的代码无法并行化?
我试图通过运行以下函数来有意耗尽 API 限制(900 次调用):
#[get("/exhaust")]
pub async fn exhaust(_pool: web::Data<PgPool>, config: web::Data<Arc<Settings>>) -> impl Responder {
let mut handles = vec![];
for i in 1..900 {
let inner_config = config.clone();
let handle = thread::spawn(move || async move {
println!("running thread {}", i);
get_single_tweet(inner_config.as_ref().deref(), "1401287393228038149")
.await
.unwrap();
});
handles.push(handle);
}
for h in handles {
h.join().unwrap().await;
}
HttpResponse::Ok()
我的机器有 16 个内核,所以我希望上面的运行速度比单线程函数快 16 倍,但事实并非如此。事实上,它的运行速度与单线程版本一样慢。
这是为什么?我错过了什么?
注意:这move || async move部分对我来说看起来有点奇怪,但我是按照编译器的建议到达那里的。由于async closures being unstable. 这可能是问题吗?
回答
此代码确实会async同步运行您的块。一个async块创建了一个实现 的类型Future,但要知道的一件事是Futures 不会自己开始运行,它们必须被await-ed 或提供给执行程序才能运行。
thread::spawn使用返回 a 的闭包调用Future不会执行它们;线程只是创建async块并返回。所以这些async块实际上并没有被执行,直到你await在循环中它们才会被执行handles,这将按顺序处理期货。
解决此问题的一种方法是join_all从futures板条箱中同时运行它们。
let mut futs = vec![];
for i in 1..900 {
let inner_config = config.clone();
futs.push(async move {
println!("running thread {}", i);
get_single_tweet(inner_config.as_ref().deref(), "1401287393228038149")
.await
.unwrap();
});
}
futures::future::join_all(futs).await;