轻作



重拾写作的乐趣

Rust async/await初探

2020.03.09

1. async/await

异步函数

async fn f0() -> u32 {
    let f1 = f1().await;
    let f2 = f2().await;
    f1 + f2
}

async fn f1() -> u32 {
    1
}

async fn f2() -> u32 {
    2
}

生成的HIR

Playground左上角点HIR

async fn f0() -> /*impl Trait*/ 
    #[lang = "from_generator"](move |mut _task_context| {{
        let _t = {
            let f1 = match #[lang = "into_future"](f1()) {
                mut __awaitee =>
                    loop {
                        match unsafe { #[lang = "poll"](#[lang = "new_unchecked"](&mut __awaitee), #[lang = "get_context"](_task_context)) } {
                            #[lang = "Ready"] { 0: result } => break result,
                            #[lang = "Pending"] {} => { }
                        }
                        _task_context = (yield ());
                    },
            };
            let f2 = match #[lang = "into_future"](f2()) {
                mut __awaitee =>
                    loop {
                        match unsafe { #[lang = "poll"](#[lang = "new_unchecked"](&mut __awaitee), #[lang = "get_context"](_task_context)) } {
                            #[lang = "Ready"] { 0: result } => break result,
                            #[lang = "Pending"] {} => { }
                        }
                        _task_context = (yield ());
                    },
            };
            f1 + f2
        };
        _t
    }})

async fn f1() -> /*impl Trait*/
    #[lang = "from_generator"](move |mut _task_context| { 
        { let _t = { 1 }; _t } 
    })

async fn f2() -> /*impl Trait*/ 
    #[lang = "from_generator"](move |mut _task_context| { 
        { let _t = { 2 }; _t } 
    })

翻译一下

async fn f0() -> impl Future {
    std::future::from_generator(move |mut _task_context| {
        let f1 = match std::future::IntoFuture::into_future(f1()) {
            mut __awaitee => 
                loop {
                    match unsafe { std::future::Future::poll(std::pin::Pin::new_unchecked(&mut __awaitee), std::future::get_context(_task_context)) } {
                        std::task::Poll::Ready(result) => break result,
                        std::task::Poll::Pending => {}
                    }
                    _task_context = (yield ());
                }
        };
        let f2 = match std::future::IntoFuture::into_future(f2()) {
            mut __awaitee => 
                loop {
                    match unsafe { std::future::Future::poll(std::pin::Pin::new_unchecked(&mut __awaitee), std::future::get_context(_task_context)) } {
                        std::task::Poll::Ready(result) => break result,
                        std::task::Poll::Pending => {}
                    }
                    _task_context = (yield ());
                }
        }
        f1 + f2
    });
}

async fn f1() -> impl Future {
    std::future::from_generator(move |mut _task_context| {
        1
    });
}

async fn f2() -> impl Future {
    std::future::from_generator(move |mut _task_context| {
        2
    });
}

可见, async函数/lambda/代码块等生成拥有Future特性的对象, await则生成yield的循环

2. yield

yield关键字会把代码重写成Generator状态机

#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};

fn main() {
    let a: i32 = 1;
    let mut generator = move || {
        println!("start");
        yield a + 2;
        println!("Hello");
        yield a * 2;
        println!("world!");
    };

    Pin::new(&mut generator).resume(());
    Pin::new(&mut generator).resume(());
}

上述代码会生成下面类似代码

use std::ops::Generator;
use std::ops::GeneratorState;
use std::pin::Pin;

enum GeneratorStateMachine {
    Enter(i32),
    Yield1(i32),
    Yield2(i32),
    Exit,
}

impl Generator for GeneratorStateMachine {
    type Yield = i32;
    type Return = ();
    fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
        // lets us get ownership over current state
        match std::mem::replace(self, GeneratorStateMachine::Exit) {
            GeneratorStateMachine::Enter(a) => {
                println!("start");
                /*---- code before yield 1 ----*/
                *self = GeneratorStateMachine::Yield1(a + 2);
                GeneratorState::Yield(a)
            }
            GeneratorStateMachine::Yield1(a) => {
                /*----- code after yield 1 -----*/
                println!("Hello");
                *self = GeneratorStateMachine::Yield2(a * 2);
                /*----- code before yield 2 -----*/
                GeneratorState::Yielded(a * 2)
            }
            GeneratorStateMachine::Yield2(_) => {
                /*----- code after yield 2 -----*/
                println!("world!");
                *self = GeneratorStateMachine::Exit;
                GeneratorState::Complete(())
            }
            GeneratorStateMachine::Exit => 
                panic!("Can't advance an exited generator!")
        }
    }
}

fn main() {
    let a: i32 = 1;
    let mut generator = move || {
        GeneratorStateMachine::Enter(a)
    };

    Pin::new(&mut generator).resume(()); // 1 + 2 = 3
    Pin::new(&mut generator).resume(()); // 3 * 2 = 6
}

这种实现方式的特点是, 状态对象捕获和储存变量到自身, 无需切换上下文(CPU状态保存和恢复的消耗), 无动态堆/栈分配, 完全契合rust零开销抽象的原则

参考

generators

发表评论