面试题答案
一键面试同步函数调用原理
- 调用栈执行:同步函数调用在调用栈上顺序执行。当一个函数被调用时,它的相关信息(如参数、局部变量等)被压入调用栈,函数执行完毕后从栈中弹出。例如:
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let result = add(2, 3);
println!("The result is: {}", result);
}
在这个例子中,main
函数调用add
函数,add
函数执行完毕返回结果后,main
函数继续执行后续代码。
2. 阻塞执行:在函数执行期间,调用线程会被阻塞,直到函数返回。这意味着在add
函数执行时,main
函数中add
调用之后的代码不会执行,直到add
返回结果。
异步函数调用与同步函数调用的区别
- 非阻塞执行:异步函数调用不会阻塞调用线程。异步函数在执行时,遇到
await
关键字会暂停执行,将控制权交回给调用者(通常是一个事件循环),允许其他任务继续执行。例如:
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture {
state: i32,
}
impl Future for MyFuture {
type Output = i32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.state < 10 {
self.state += 1;
Poll::Pending
} else {
Poll::Ready(self.state)
}
}
}
async fn async_function() -> i32 {
let future = MyFuture { state: 0 };
future.await
}
在这个异步函数async_function
中,await
会暂停函数执行,直到MyFuture
完成。
2. 状态机实现:异步函数会被编译器转换为状态机。每次await
都会记录当前状态,以便后续从暂停的地方继续执行。而异步函数返回的Future
实际上是这个状态机的包装。
为何异步函数调用不能简单复用同步函数调用原理
- 阻塞问题:如果异步函数复用同步函数的调用栈执行方式,就会导致在
await
时阻塞线程,无法实现异步的并发效果。例如,在一个处理多个网络请求的异步程序中,如果使用同步调用原理,一个请求的等待(如等待网络响应)会阻塞整个线程,其他请求也无法处理。 - 执行流程管理:同步函数调用栈是顺序执行且一次性的,而异步函数需要多次暂停和恢复执行,同步调用原理无法满足这种灵活的执行流程管理需求。
通过上述分析可知,同步函数和异步函数在机制上有着本质区别,异步函数不能简单复用同步函数的调用原理。