< 返回版块

Mercury 发表于 2022-08-15 14:27

最近写后端,tokio用的比较多,但用归用,都是知其然不知其所以然,最近有空,就啃了下tokio官方的教程。看完后,懂了部分,但有了更多困惑,请高手帮忙解答纠正下。

MiniTokio的例子中,其运行时包含两个队列SenderReceiverTaskspawn时会先将自己先塞入Sender队列中,完成初始化。

之后MiniTokio调用run方法,遍历Receiver队列,执行里面Taskpoll方法,并创建Waker

Taskpoll实际上是调用FuturepollFuture是一个状态机,如果在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);
}

评论区

写评论
作者 Mercury 2022-08-16 08:57

多谢,已经看完样例。又查了下,今年社区其实有大佬分享了async/await的实现方法,发现神器HIR,编译器的确是将异步代码做成了状态机,揽下了好多脏活累活。

--
👇
7sDream: Q1. 会。如果在 Async 函数里调用标准库版本的 sleep,就会阻塞住一个执行器的线程。 Q2. Async 函数会被编译器转换为一个状态机,在每一个 .await 的地方都有有一个状态,编译器会在给这个状态机实现 Future Trait 的时候控制状态转换。

官方论坛上有个具体的 Async 函数如何被 desugar 的样例

7sDream 2022-08-15 16:51

Q1. 会。如果在 Async 函数里调用标准库版本的 sleep,就会阻塞住一个执行器的线程。 Q2. Async 函数会被编译器转换为一个状态机,在每一个 .await 的地方都有有一个状态,编译器会在给这个状态机实现 Future Trait 的时候控制状态转换。

官方论坛上有个具体的 Async 函数如何被 desugar 的样例

1 共 2 条评论, 1 页