BruceChen7 / gitblog

My blog
6 stars 1 forks source link

async和await的概念 #55

Open BruceChen7 opened 1 year ago

BruceChen7 commented 1 year ago

参考资料

async runtime

std::future::Future 的定义

use std::pin::Pin;
use std::task::{Context, Poll};

pub trait Future {
    type Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context)
        -> Poll<Self::Output>;
}

示例

struct MyFuture {
    id: u32,
    start: Instant,
    duration: Duration,
}

fn block_on<F: Future>(fut: F) -> F::Output {
    let mut fut = pin!(fut);
    let t = thread::current();
    let waker = Arc::new(ThreadWaker(t)).into();
    let mut cx = Context::from_waker(&waker);
    loop {
        match fut.as_mut().poll(&mut cx) {
            Poll::Ready(res) => return res,
            Poll::Pending => thread::park(),
        }
    }
}
struct ThreadWaker(Thread);
impl Wake for ThreadWaker {
    fn wake(self: Arc<Self>) {
        self.0.unpark();
    }
}

impl Future for MyFuture {
    type Output = ();
    fn poll(&mut self, cx: &mut Context) -> Poll<Self::Output> {
        println!("Polling {} {}", self.id, chrono::Utc::now());
        let now = Instant::now();
        let id = self.id;
        let expect = self.start + self.duration;
        if expect > now {
            let duration = expect - now;
            let waker = cx.waker().clone();
            thread::spawn(move || {
                thread::sleep(duration);
                // 用来唤醒
                waker.wake();
            });
            println!("Waking {id} {}", chrono::Utc::now());
            Poll::Pending
        } else {
            println!("Done {} {}", id, chrono::Utc::now());
            Poll::Ready(())
        }

    }
}

fn main() {
    println!("Start {}", chrono::Utc::now());
    block_on(MyFuture {
        id: 1,
        start: Instant::now(),
        duration: Duration::from_millis(1000 * 10),
    });
    println!("End {}", chrono::Utc::now());
}

多个 futures

如果想 Future 的产生和计算都在同一个线程中

let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
    let local = tokio::task::LocalSet::new();
    let rc = Rc::new(42);
    local.run_until(async move {
        println!("rc={rc}");
    }).await;
});

Waker API

pub fn waker_fn<F: Fn() + Send + Sync + 'static>(f: F) -> Waker {
    Waker::from(Arc::new(Helper(f)))
}

struct Helper<F>(F);

impl<F: Fn() + Send + Sync + 'static> Wake for Helper<F> {
    fn wake(self: Arc<Self>) {
        (self.0)();
    }

    fn wake_by_ref(self: &Arc<Self>) {
        (self.0)();
    }
}

pub struct Waker {
    waker: RawWaker,
}

pub struct RawWaker {
    data: *const (),
    vtable: &'static RawWakerVTable,
}

pub struct RawWakerVTable {
    clone: unsafe fn(*const ()) -> RawWaker,
    wake: unsafe fn(*const ()),
    wake_by_ref: unsafe fn(*const ()),
    drop: unsafe fn(*const ()),
}

impl Waker {
    pub fn wake_by_ref(&self) {
        unsafe {
            (self.waker.vtable.wake_by_ref)(self.waker.data);
        }
    }
    pub fn wake(self) {
        let waker = self.waker.vtable.wake;
        let data = self.waker.data;
        crate::mem::forget(self);
        unsafe {
            (waker)(data)
        };
    }
}

在使用 async fn main 下生成的 Future 如下

use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};

enum MainFuture {
    // Initialized, never polled
    State0,
    // Waiting on `Delay`, i.e. the `future.await` line.
    State1(Delay),
    // The future has completed.
    Terminated,
}

impl Future for MainFuture {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>)
        -> Poll<()>
    {
        use MainFuture::*;

        loop {
            match *self {
                State0 => {
                    let when = Instant::now() +
                        Duration::from_millis(10);
                    let future = Delay { when };
                    *self = State1(future);
                }
                State1(ref mut my_future) => {
                    match Pin::new(my_future).poll(cx) {
                        Poll::Ready(out) => {
                            assert_eq!(out, "done");
                            *self = Terminated;
                            return Poll::Ready(());
                        }
                        Poll::Pending => {
                            return Poll::Pending;
                        }
                    }
                }
                Terminated => {
                    panic!("future polled after completion")
                }
            }
        }
    }
}

执行者 (Executors)

Wakers

type/rust #public