面试题答案
一键面试设计思路
- 错误类型定义:定义一个统一的错误类型,将不同任务可能出现的错误都包裹在这个类型中。可以使用
enum
来实现,这样不同任务的错误都能被统一处理。 - 并发执行:使用
tokio
等异步运行时库的join!
宏或者futures::future::join_all
来并发执行多个异步任务。 - 错误处理:在每个异步任务内部,使用
Result
类型来处理可能出现的错误。当使用join!
或join_all
时,需要对每个任务返回的Result
进行处理,确保一个任务出错不会影响其他任务的执行,同时能收集所有错误。
关键代码片段
use std::error::Error;
use futures::future::join_all;
use tokio;
// 定义统一的错误类型
#[derive(Debug)]
enum MyError {
Task1Error(String),
Task2Error(String),
// 其他任务的错误类型
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MyError::Task1Error(s) => write!(f, "Task1 error: {}", s),
MyError::Task2Error(s) => write!(f, "Task2 error: {}", s),
}
}
}
impl Error for MyError {}
// 模拟异步任务1
async fn task1() -> Result<(), MyError> {
// 模拟任务执行
if true {
Err(MyError::Task1Error("Task1 failed".to_string()))
} else {
Ok(())
}
}
// 模拟异步任务2
async fn task2() -> Result<(), MyError> {
// 模拟任务执行
if true {
Err(MyError::Task2Error("Task2 failed".to_string()))
} else {
Ok(())
}
}
#[tokio::main]
async fn main() {
let tasks = vec![task1(), task2()];
let results = join_all(tasks).await;
let mut errors = Vec::new();
for result in results {
if let Err(e) = result {
errors.push(e);
}
}
if!errors.is_empty() {
for error in errors {
eprintln!("Error: {}", error);
}
std::process::exit(1);
}
}
在上述代码中:
- 定义了
MyError
枚举类型来统一处理不同任务的错误。 task1
和task2
模拟了两个异步任务,它们都返回Result<(), MyError>
。- 在
main
函数中,使用join_all
并发执行任务,并遍历结果收集所有错误,最后统一处理错误。这样既保证了并发安全,又高效地处理了错误,对程序性能影响较小。