美文网首页
理解 rust 中的 futures(三)

理解 rust 中的 futures(三)

作者: 西门早柿 | 来源:发表于2021-02-20 22:10 被阅读0次

    构建我们自己的 future

    从上层来看,我们需要实现以下几个部分来让 future 工作:一个 runner,future trait 以及 poll type。

    首先是 runner

    如果没有一个方式来执行它的话,我们的 future 什么都不会做。既然我们要实现自己的 futures,因此我们也需要实现自己的 runner。在这个练习中,我们会近似的模拟异步调用,而不是真正的异步。futures 是基于拉模式,而不是推模式,这使得 futures 的抽象是零成本的,同时也意味着一旦 futures 被开始轮询,它有责任在自己准备好下次轮询的时候通知 executor。了解这个过程是怎样工作的细节对理解 futures 是如何创建并串联起来的很重要。我们的 executor 是一个很简略的实现,它只能运行一个 future,并且不能执行真正意义上的异步调用。Tokio 的文档中有更多关于 future 运行时的信息。

    下面是我们对 executor 的一个简单实现:

    use std::cell::RefCell;
    
    thread_local!(static NOTIFY: RefCell<bool> = RefCell::new(true));
    
    struct Context<'a> {
        waker: &'a Waker,
    }
    
    impl<'a> Context<'a> {
        fn from_waker(waker: &'a Waker) -> Self {
            Context { waker }
        }
    
        fn waker(&self) -> &'a Waker {
            &self.waker
        }
    }
    
    struct Waker;
    
    impl Waker {
        fn wake(&self) {
            NOTIFY.with(|f| *f.borrow_mut() = true)
        }
    }
    
    fn run<F>(mut f: F) -> F::Output
    where
        F: Future,
    {
        NOTIFY.with(|n| loop {
            if *n.borrow() {
                *n.borrow_mut() = false;
                let ctx = Context::from_waker(&Waker);
                if let Poll::Ready(val) = f.poll(&ctx) {
                    return val;
                }
            }
        })
    }
    

    run 是类型 F 的一个泛型函数,其中 F 是 future 类型。返回类型是 Output,是在 Future trait 中定义的关联类型,这个我们后面再看。

    这个函数的内容是对真正 runner 所做工作的模拟。它会一直循环直到收到 future 准备好再次轮询的通知。当 future 准备好的时候,run 函数返回(这里 future 准备好被再次轮询和 future 准备好,是两个不同的概念)。ContextWaker 类型是对 future::task 模块中定义的同步类型的模型,原始定义可以在这里找到。这们在这里的定义是为了使程序可以通过编译,具体的讨论超出了我们这篇博客的范围,你们可以自己去研究它们是如何工作的。

    Poll 像下面定义的一个简单的泛型枚举类型。

    enum Poll<T> {
        Ready(T),
        Pending
    }
    

    相关文章

      网友评论

          本文标题:理解 rust 中的 futures(三)

          本文链接:https://www.haomeiwen.com/subject/lzdcfltx.html