pub fn e_generator()
Expand description
§异步实现细节:生成器 与 协程
§历史
处理异步事件的三种方式:
- Callback
- Promise/Future
- async/await
async/await 是目前体验最好的方式,Rust 要支持它并不容易。
§async/await 语法介绍
参考:Asynchronous Programming in Rust
async
两种用法:async fn
函数 和 async {}
块。
// async 函数,真正会返回 `Future<Output = u8>`,而不是表面看上去的 `u8`
async fn foo() -> u8 { 5 }
// async 块用法,返回 `impl Future<Output = u8>`
fn bar() -> impl Future<Output = u8> {
// 这里 `async` 块返回 `impl Future<Output = u8>`
async {
let x: u8 = foo().await;
x + 5
}
}
await
将暂停当前函数的执行,直到执行者将 Future 结束为止。这为其他 Future 任务提供了计算的机会。
§生成器
Future 底层实现依赖于 生成器。 async/await
对应底层生成器 resume/yield
。
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let mut gen = || {
yield 1;
yield 2;
yield 3;
return 4;
};
// for _ in 0..4 {
// // 为了给嵌入式支持异步,多传入了一个空的unit给resume方法
// let c = Pin::new(&mut gen).resume(());
// println!("{:?}", c);
// }
let c = Pin::new(&mut gen).resume(());
println!("{:?}", c);
let c = Pin::new(&mut gen).resume(());
println!("{:?}", c);
let c = Pin::new(&mut gen).resume(());
println!("{:?}", c);
let c = Pin::new(&mut gen).resume(());
println!("{:?}", c);
}
生成等价代码:
#![allow(unused)]
#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
enum __Gen {
// (0) 初始状态
Start,
// (1) resume方法执行以后
State1(State1),
// (2) resume方法执行以后
State2(State2),
// (3) resume方法执行以后
State3(State3),
// (4) resume方法执行以后,正好完成
Done
}
struct State1 { x: u64 }
struct State2 { x: u64 }
struct State3 { x: u64 }
impl Generator for __Gen {
type Yield = u64;
type Return = u64;
fn resume(self: Pin<&mut Self>, _: ()) -> GeneratorState<u64, u64> {
let mut_ref = self.get_mut();
match std::mem::replace(mut_ref, __Gen::Done) {
__Gen::Start => {
*mut_ref = __Gen::State1(State1{x: 1});
GeneratorState::Yielded(1)
}
__Gen::State1(State1{x: 1}) => {
*mut_ref = __Gen::State2(State2{x: 2});
GeneratorState::Yielded(2)
}
__Gen::State2(State2{x: 2}) => {
*mut_ref = __Gen::State3(State3{x: 3});
GeneratorState::Yielded(3)
}
__Gen::State3(State3{x: 3}) => {
*mut_ref = __Gen::Done;
GeneratorState::Complete(4)
}
_ => {
panic!("generator resumed after completion")
}
}
}
}
fn main(){
let mut gen = {
__Gen::Start
};
for _ in 0..4 {
println!("{:?}", unsafe{ Pin::new(&mut gen).resume(())});
}
}
生成器基本用法:
#![allow(unused)]
#![feature(generators, generator_trait)]
use std::pin::Pin;
use std::ops::Generator;
pub fn up_to(limit: u64) -> impl Generator<Yield = u64, Return = u64> {
move || {
for x in 0..limit {
yield x;
}
return limit;
}
}
fn main(){
let a = 10;
let mut b = up_to(a);
unsafe {
for _ in 0..=10{
let c = Pin::new(&mut b).resume(());
println!("{:?}", c);
}
}
}
生成器变身为迭代器:
#![allow(unused)]
#![feature(generators, generator_trait)]
use std::pin::Pin;
use std::ops::{Generator, GeneratorState};
pub fn up_to() -> impl Generator<Yield = u64, Return = ()> {
move || {
let mut x = 0;
loop {
x += 1;
yield x;
}
return ();
}
}
fn main(){
let mut gen = up_to();
unsafe {
for _ in 0..10{
match Pin::new(&mut gen).resume(()) {
GeneratorState::Yielded(i) => println!("{:?}", i),
_ => println!("Completed"),
}
}
}
}
生成器变身为 Future:
#![allow(unused)]
#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
pub fn up_to(limit: u64) -> impl Generator<Yield = (), Return = Result<u64, ()>> {
move || {
for x in 0..limit {
yield ();
}
return Ok(limit);
}
}
fn main(){
let limit = 2;
let mut gen = up_to(limit);
unsafe {
for i in 0..=limit{
match Pin::new(&mut gen).resume(()) {
GeneratorState::Yielded(v) => println!("resume {:?} : Pending", i),
GeneratorState::Complete(v) => println!("resume {:?} : Ready", i),
}
}
}
}
跨 yield 借用会报错:
#![allow(unused)]
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
pub fn up_to(limit: u64) -> impl Generator<Yield = u64, Return = u64> {
move || {
let a = 5;
let ref_a = &a;
for x in 0..limit {
yield x;
if x == 5{
yield *ref_a;
}
}
return limit;
}
}
fn main(){
let a = 10;
let mut b = up_to(a);
unsafe {
for _ in 0..=10{
let c = Pin::new(&mut b).resume(());
println!("{:?}", c);
}
}
}
自引用结构:
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main(){
let mut generator = move || {
let to_borrow = String::from("Hello");
let borrowed = &to_borrow;
// error[E0626]: borrow may still be in use when generator yields
yield borrowed.len();
println!("{} world!", borrowed);
};
}
模拟底层实现 generator :
#![allow(unused)]
#![feature(never_type)] // Force nightly compiler to be used in playground
// by betting on it's true that this type is named after it's stabilization date...
pub fn main() {
let mut gen = GeneratorA::start();
let mut gen2 = GeneratorA::start();
if let GeneratorState::Yielded(n) = gen.resume() {
println!("Got value {}", n);
}
// std::mem::swap(&mut gen, &mut gen2); // <--- Big problem!
if let GeneratorState::Yielded(n) = gen2.resume() {
println!("Got value {}", n);
}
// This would now start gen2 since we swapped them.
if let GeneratorState::Complete(()) = gen.resume() {
()
};
if let GeneratorState::Complete(()) = gen2.resume() {
()
};
}
enum GeneratorState<Y, R> {
Yielded(Y),
Complete(R),
}
trait Generator {
type Yield;
type Return;
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
}
enum GeneratorA {
Enter,
Yield1 {
to_borrow: String,
borrowed: *const String,
},
Exit,
}
impl GeneratorA {
fn start() -> Self {
GeneratorA::Enter
}
}
impl Generator for GeneratorA {
type Yield = usize;
type Return = ();
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
match self {
GeneratorA::Enter => {
let to_borrow = String::from("Hello");
let borrowed = &to_borrow;
let res = borrowed.len();
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
// We set the self-reference here
if let GeneratorA::Yield1 {to_borrow, borrowed} = self {
*borrowed = to_borrow;
}
GeneratorState::Yielded(res)
}
GeneratorA::Yield1 {borrowed, ..} => {
let borrowed: &String = unsafe {&**borrowed};
println!("{} world", borrowed);
*self = GeneratorA::Exit;
GeneratorState::Complete(())
}
GeneratorA::Exit => panic!("Can't advance an exited generator!"),
}
}
}
上面代码在 Safe Rust 下是存在问题的,有 UB 风险。
用 Pin 修正:
#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
pub fn main() {
// 使用 static 关键字创建 immovable 生成器
let gen1 = static || {
let to_borrow = String::from("Hello");
let borrowed = &to_borrow;
yield borrowed.len();
println!("{} world!", borrowed);
};
let gen2 = static || {
let to_borrow = String::from("Hello");
let borrowed = &to_borrow;
yield borrowed.len();
println!("{} world!", borrowed);
};
let mut pinned1 = Box::pin(gen1);
let mut pinned2 = Box::pin(gen2);
if let GeneratorState::Yielded(n) = pinned1.as_mut().resume(()) {
println!("Gen1 got value {}", n);
}
if let GeneratorState::Yielded(n) = pinned2.as_mut().resume(()) {
println!("Gen2 got value {}", n);
};
let _ = pinned1.as_mut().resume(());
let _ = pinned2.as_mut().resume(());
}
第三方库 genawaiter:stable rust 实现 generator 。