面试题答案
一键面试use reqwest;
use futures::future::{join_all, BoxFuture};
use std::sync::Arc;
use std::time::Duration;
async fn fetch_api(url: &str) -> Result<String, reqwest::Error> {
let client = reqwest::Client::new();
client.get(url)
.timeout(Duration::from_secs(10))
.send()
.await?
.text()
.await
}
async fn run_api_calls(api_urls: &[&str]) -> Result<Vec<String>, reqwest::Error> {
let semaphore = Arc::new(tokio::sync::Semaphore::new(5));
let mut tasks = Vec::new();
for url in api_urls {
let semaphore = semaphore.clone();
tasks.push(tokio::spawn(async move {
let permit = semaphore.acquire().await.expect("Failed to acquire permit");
let result = fetch_api(url).await;
drop(permit);
result
}));
}
let results = join_all(tasks).await;
let mut final_results = Vec::new();
for result in results {
final_results.push(result??);
}
Ok(final_results)
}
#[tokio::main]
async fn main() {
let api_urls = &["http://example.com/api1", "http://example.com/api2", "http://example.com/api3"];
match run_api_calls(api_urls).await {
Ok(results) => println!("Results: {:?}", results),
Err(e) => eprintln!("Error: {}", e),
}
}
性能优化
- 异步任务处理:
- 使用
tokio::spawn
将每个API调用包装成独立的异步任务。 - 使用
futures::future::join_all
等待所有任务完成,这可以高效地管理多个异步任务,不会阻塞主线程。
- 使用
- 错误处理:
- 在
fetch_api
函数中,使用?
操作符处理reqwest::Error
,将错误向上传递。 - 在
run_api_calls
函数中,对每个任务的结果进行?
操作,收集所有成功的结果,若有任何一个任务失败则整个操作失败。
- 在
- 资源管理:
- 使用
tokio::sync::Semaphore
控制并发数量,确保同时最多有5个请求在执行,避免资源耗尽。 - 在
fetch_api
函数中,设置reqwest::Client
的超时时间,防止请求长时间挂起占用资源。
- 使用
通过以上方式,程序能够高效地并发调用多个API,同时合理管理资源和处理错误。