作者:再生Solo_868 | 来源:互联网 | 2024-11-13 15:43
我尝试通过运行以下函数来有意耗尽 API 限制(900 次调用):
#[get("/exhaust")]
pub async fn exhaust(_pool: web::Data, config: web::Data>) -> 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
类型的对象,但需要注意的是,Future
不会自动开始运行,它们必须被await
或提供给执行器才能运行。
thread::spawn
使用返回Future
的闭包调用并不会执行这些Future
;线程只是创建async
块并返回。因此,这些async
块实际上并未被执行,直到你在循环中await
它们,这将按顺序处理这些Future
。
解决此问题的一种方法是使用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;
通过这种方式,所有Future
将并行执行,从而实现真正的并行化。