Programación asincrónica de Rust: biblioteca estándar oficial

El código de la biblioteca estándar se encuentra en https://github.com/rust-lang/rust/tree/master/library
aquí usando la última versión 1.45.2

Paquetes involucrados

std::future::*

Correspondiente src/libstd/future.rs, proporciona principalmente la siguiente API

pub use core::future::Future;
pub use core::future::{
    
    from_generator, get_context, ResumeTy};
pub use core::future::{
    
    pending, ready, Pending, Ready};
pub use core::future::IntoFuture;

core::futuresrc/libcore/futureDirectorio correspondiente , existen los siguientes archivos

future.rs      
into_future.rs 
mod.rs         
pending.rs     
poll_fn.rs     
ready.rs

std::poll::* constd::wake::*

Correspondiente a src / libcore / task / mod.rs, proporciona principalmente la siguiente API

mod poll;
pub use self::poll::Poll;

mod wake;
pub use self::wake::{
    
    Context, RawWaker, RawWakerVTable, Waker};

directorio src / libcore / task, existen los siguientes archivos

mod.rs
poll.rs
wake.rs

Futuro

src / libcore / future / future.rs

#[lang = "future_trait"]
pub trait Future {
    
    
    type Output;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

El rasgo Future es el rasgo más básico de la programación asincrónica. Tiene un método de encuesta. El segundo parámetro de la encuesta es Contexto. El contexto contiene una función de activación. El método de encuesta devuelve Poll :: Ready o Poll :: Pending.

Contexto

src / libcore / task / wake.rs

El contexto de las tareas asincrónicas es utilizado por el método de encuesta de Future. En la actualidad, solo Waker se empaqueta internamente. No se descarta que se agreguen otras cosas en el futuro.

pub struct Context<'a> {
    
    
    waker: &'a Waker,
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    
    
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
    
    
        Context {
    
     waker, _marker: PhantomData }
    }
    #[inline]
    pub fn waker(&self) -> &'a Waker {
    
    
        &self.waker
    }
}

Waker

src / libcore / task / wake.rs

La función de activación se utiliza para notificar al ejecutor que la tarea se puede ejecutar. Implementa Enviar, Sincronizar, Clonar y encapsular la instancia de RawWaker.

pub struct Waker {
    
    
    waker: RawWaker,
}

impl Unpin for Waker {
    
    }
unsafe impl Send for Waker {
    
    }
unsafe impl Sync for Waker {
    
    }
impl Clone for Waker {
    
    
    fn clone(&self) -> Self {
    
    
        Waker {
    
    
            waker: unsafe {
    
     (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

RawWaker

src / libcore / task / wake.rs

#[derive(PartialEq, Debug)]
pub struct RawWaker {
    
    
    data: *const (),
    vtable: &'static RawWakerVTable,
}

RawWakerVTable

src / libcore / task / wake.rs

Una tabla de punteros de función virtual (vtable), utilizada en RawWaker

#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    
    

    clone: unsafe fn(*const ()) -> RawWaker,

    wake: unsafe fn(*const ()),

    wake_by_ref: unsafe fn(*const ()),

    drop: unsafe fn(*const ()),
}

Encuesta

src / libcore / task / poll.rs

Valor de retorno del método de encuesta de Future

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Poll<T> {
    
    
    Ready(T),
    Pending,
}

Listo

src / libcore / future / ready.rs

Cree un futuro con valores listos de inmediato

#[derive(Debug, Clone)]
pub struct Ready<T>(Option<T>);

impl<T> Unpin for Ready<T> {
    
    }

impl<T> Future for Ready<T> {
    
    
    type Output = T;

    #[inline]
    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
    
    
        Poll::Ready(self.0.take().expect("Ready polled after completion"))
    }
}
pub fn ready<T>(t: T) -> Ready<T> {
    
    
    Ready(Some(t))
}

p.ej

 #![feature(future_readiness_fns)]
 use core::future;
 async fn run() {
    
    
   let a = future::ready(1);
   assert_eq!(a.await, 1);
}

Pendiente

src / libcore / future / pendiente.rs

Crea un futuro que nunca se podrá completar (calcular)

#[derive(Debug)]
pub struct Pending<T> {
    
    
    _data: marker::PhantomData<T>,
}

pub fn pending<T>() -> Pending<T> {
    
    
    Pending {
    
     _data: marker::PhantomData }
}
impl<T> Future for Pending<T> {
    
    
    type Output = T;

    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
    
    
        Poll::Pending
    }
}

p.ej

#![feature(future_readiness_fns)]
use core::future;
async fn run() {
    
    
	let future = future::pending();
	let () = future.await;
    unreachable!();
}

En el futuro

src / libcore / future / into_future.rs

Convertir un tipo en futuro

pub trait IntoFuture {
    
    
    type Output;
    type Future: Future<Output = Self::Output>;
    fn into_future(self) -> Self::Future;
}

impl<F: Future> IntoFuture for F {
    
    
    type Output = F::Output;
    type Future = F;
    fn into_future(self) -> Self::Future {
    
    
        self
    }
}

from_generator

src / libcore / future / mod.rs

  • El compilador convierte finalmente el bloque de código ansyc en un generador. El generador se incluirá en GenFuture. GenFuture implementa Future. El método resume del generador se llama en poll. Si está en el estado, devuelve Poll :: Pending , si está completo. (x), devuelve Poll :: Ready (x)
  • El significado de ResumeTy: el generador no se puede implementar for<'a, 'b> Generator<&'a mut Context<'b>>, por lo que se necesita un puntero sin formato, y el puntero sin formato o NonNull no se puede combinar SendconSync
#[derive(Debug, Copy, Clone)]
pub struct ResumeTy(NonNull<Context<'static>>);

unsafe impl Send for ResumeTy {
    
    }

unsafe impl Sync for ResumeTy {
    
    }

pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
    T: Generator<ResumeTy, Yield = ()>,
{
    
    
    struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
    impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {
    
    }

    impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
    
    
        type Output = T::Return;
        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
    
    
            // Safety:!Unpin + !Drop
            let gen = unsafe {
    
     Pin::map_unchecked_mut(self, |s| &mut s.0) };
            match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
    
    
                GeneratorState::Yielded(()) => Poll::Pending,
                GeneratorState::Complete(x) => Poll::Ready(x),
            }
        }
    }
    GenFuture(gen)
}


pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
    
    
    &mut *cx.0.as_ptr().cast()
}

Supongo que te gusta

Origin blog.csdn.net/kk3909/article/details/108155264
Recomendado
Clasificación