最近写后端,tokio用的比较多,但用归用,都是知其然不知其所以然,最近有空,就啃了下tokio官方的教程。看完后,懂了部分,但有了更多困惑,请高手帮忙解答纠正下。
MiniTokio的例子中,其运行时包含两个队列Sender
和Receiver
,Task
在spawn
时会先将自己先塞入Sender
队列中,完成初始化。
之后MiniTokio调用run
方法,遍历Receiver
队列,执行里面Task
的poll
方法,并创建Waker
。
Task
的poll
实际上是调用Future
的poll
。Future
是一个状态机,如果在poll
的时候没有执行完毕,就会返回一个Poll::Pending
,同时调用Waker
,将Task
塞回Sender
队列中。
MiniTokio继续获取Receiver
中的Task
,执行下一个任务,从而实现异步功能。
-
Q1: 按照这个模型,如果我某个future里面有一个action极其耗时,在
poll
的时候,会否堵塞进程? -
Q2: 在future中
spawn
另一个task时,并没有显式的返回Poll::Pending
,程序是如何中断当前的task
,又是如何在后面又恢复继续执行的呢?
async fn outter() {
let foo = String::from("foo");
tokio::time::sleep(Duration::from_secs(10)).await; // sleep task被塞进`Sender`队列,后面的print语句如何实现不执行并退出,同时谁产生了waker去唤醒它,并继续执行下面的语句,上下文又保存在哪?
println!("{}",foo);
}
1
共 2 条评论, 1 页
评论区
写评论多谢,已经看完样例。又查了下,今年社区其实有大佬分享了async/await的实现方法,发现神器HIR,编译器的确是将异步代码做成了状态机,揽下了好多脏活累活。
--
👇
7sDream: Q1. 会。如果在 Async 函数里调用标准库版本的 sleep,就会阻塞住一个执行器的线程。 Q2. Async 函数会被编译器转换为一个状态机,在每一个
.await
的地方都有有一个状态,编译器会在给这个状态机实现 Future Trait 的时候控制状态转换。官方论坛上有个具体的 Async 函数如何被 desugar 的样例。
Q1. 会。如果在 Async 函数里调用标准库版本的 sleep,就会阻塞住一个执行器的线程。 Q2. Async 函数会被编译器转换为一个状态机,在每一个
.await
的地方都有有一个状态,编译器会在给这个状态机实现 Future Trait 的时候控制状态转换。官方论坛上有个具体的 Async 函数如何被 desugar 的样例。