状态机
在上一节中,我们讲到生成器执行到 yield
表达式时,会在这个 yield
点挂起,当再次激活生成器时会在挂起的 yield
点恢复运行,那么生成器是怎么保存在 yield
点挂起时的状态呢?
事实上,编译器会把生成器转化为一个状态机,状态机中会保存每一个 yield
点的生成器的执行状态。
假如我们写了一个如下所示的生成器:
#![feature(generators, generator_trait)] use std::pin::Pin; use std::ops::{Generator, GeneratorState}; fn main() { let mut gen = || { yield 1; yield 2; () }; loop { match Pin::new(&mut gen).resume(()) { GeneratorState::Yielded(y) => println!("Yielded: {}", y), GeneratorState::Complete(c) => { println!("Complete: {:?}", c); break; } } } }
编译器会把生成器转化为下面的代码:
#![feature(generators, generator_trait)] use std::mem; use std::pin::Pin; use std::ops::{Generator, GeneratorState}; fn main() { let mut gen = MyGenerator::new(); loop { match Pin::new(&mut gen).resume(()) { GeneratorState::Yielded(y) => println!("Yielded: {}", y), GeneratorState::Complete(c) => { println!("Complete: {:?}", c); break; } } } } enum MyGenerator { Enter, State1(i32), State2(i32), Exit } impl<R> Generator<R> for MyGenerator { type Yield = i32; type Return = (); fn resume(self: Pin<&mut Self>, _arg: R) -> GeneratorState<Self::Yield, Self::Return> { let mut_gen = self.get_mut(); match mem::replace(mut_gen, MyGenerator::Exit) { MyGenerator::Enter => { *mut_gen = MyGenerator::State1(1); GeneratorState::Yielded(1) } MyGenerator::State1(_) => { *mut_gen = MyGenerator::State2(2); GeneratorState::Yielded(2) } MyGenerator::State2(_) => { *mut_gen = MyGenerator::Exit; GeneratorState::Complete(()) } MyGenerator::Exit => panic!("Generator has been completed.") } } } impl MyGenerator { fn new() -> Self { Self::Enter } }
同时,由于每个 async
函数最终都会生成一个状态机,并且每个可执行文件都会捆绑一个异步运行时,这会导致异步的 Rust 代码在编译后产生更大的二进制体积,这也是 async
Rust 的一个小缺点。