Rust异步机制
Future 抽象
Rust中对异步Task的核心抽象为Future trait,源码如下:
1 | pub trait Future { |
Future trait描述状态机对外暴露的接口,用户或Runtime通过poll方法推动状态机,返回执行结果,
遇到了阻塞 Pending
执行完毕 Ready+返回值
async和await本质上是一个语法糖,我们可以手动实现Future 来实现异步
1 | fn do_future -> MyFuture { MyFuture } |
我们注意到 poll 方法中有一个 Context,源码如下:
1 | pub struct Context<'a> { |
Context中的 waker 就是用于唤醒 Task,他是由 Runtime 构造并且由 Runtime 调用
Future状态机运转流程
Rust异步任务的大致流程包括:
- 运行时组件内部首先将IO注册到Poller中(后面会讲到Poller)
- 之后将任务放入(spawn)运行时的任务队列(Task queue)中
- 运行时不停地从任务内部取出任务并且执行
- 任务执行poll方法,例如执行 read/receive/write 系统调用
4.1. 如果IO没有准备好(Kernel返回WOUND_BLOCK),那么便会返回Pending
4.2. IO准备好了(Kernel返回Ok(fd)),返回Ready < T > - 接着执行Task queue中的其他任务,没有任务那么就进入wait
- 进入wait之后Poller会通过系统调用(例如epoll_wait),根据返回的IO找到之前放入的Waker,Waker执行wake方法将先前Pending的任务放回Task queue
Runtime核心组件
Runtime的核心组件包括IO组件,Executor以及Reactor
IO组件主要提供异步接口,将自己的fd注册到Reactor上,并在IO未准备就绪时,将waker放到关联任务中。Executor取出并执行任务(poll),并在Task queue空时转向Reactor,Reactor与Kernel打交道,在IO就绪时将关联的任务唤醒(加入Task queue),并将执行权交给Executor。