Future trait
定义:
pub trait Future {type Output;fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;}
MiniTokio
主要由三部分组成:
结构体定义:包含一个
Receiver,用于从channel中接收Task;一个Sender,用于分发给Taskpub struct MiniTokio {// 从通道中读取数据receiver: Receiver<Arc<Task>>,// 把句柄分发给 Task,让它们能把自身发送到通道里sender: Sender<Arc<Task>>,}
new()函数:创建通道,创建MiniTokio实例spawn()方法:调用Task的spawn()方法,把拿到的future实例和Sender引用发给Taskpub fn spawn<F>(&self, future: F)whereF: Future<Output = ()> + Send + 'static,{}
run()方法:从channel中取Task,然后调用其poll()方法、pub fn run(&self) {}
Task
主要由四部分组成:
结构体定义:保存了一个
future和一个Sender对象pub struct Task {future: Mutex<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>,sender: Sender<Arc<Task>>,}
spawn方法定义:用于生成Task的实例,并将自身发送到channel中pub fn spawn<F>(future: F, sender: &Sender<Arc<Task>>)whereF: Future<Output = ()> + Send + 'static, {}
poll()方法定义:用于调用自身future中的poll()方法pub fn poll(self: &Arc<Task>) {}
实现
ArcWake trait:可以使用let waker = task::waker(self.clone());,创建Waker实例impl ArcWake for Task {fn wake_by_ref(arc_self: &Arc<Self>) {}}
Task的类型
Arc<Task>:
因为Task是需要把自身发送到通道里的,所以需要有clone()方法,因此使用Arc<T>进行包装:
Future的类型
Mutex<Pin<Box<dyn Future<Output = ()> + Send>>>:
Rust允许Future可以先后被多个**Task**调度,属于多线程的访问,因此需要Sync trait,因此使用Mutex<T>进行包装Future需要Pin到堆上,因此需要使用Box::Pin包装Future类型的trait object:Future<Output = ()> + Send
重点:
async标记在异步函数前面,调用这个函数会返回一个**future**异步操作是惰性的,只调用异步函数什么都不会发生,需要一个
caller去调用这个future的poll()方法async在编译时根据await的调用被转换成状态机,状态机作为最外层的**future**也实现了Future trait,执行异步操作的过程就是层层向里执行poll()方法的过程如果当前操作未完成,则返回
**Poll::Pending**,并把当前传进来的Waker记录下来Waker是和Task相关联的,它被包装进Context中,传递给具体执行IO操作的函数(Reactor)当
I/O操作完成之后,由Reactor调用waker.wake()函数,将Task重新交给执行器executor执行器
executor再次调度这个Task中的future,推进状态此时资源是就绪状态,返回
**Poll::Ready()**
