Rust Future 教程 - Rust Future Reactor

1,440 阅读3分钟
原文链接: www.codemore.top
介绍

简单来讲reactor就是无限循环。Rust中的reactor就是这样,reactor运行future,会一遍遍的检查future的状态,直到future完成或者返回错误。循环检查时通过poll函数实现的。

实现Future

下面通过实现一个Future来讲解reactor的使用

首先实现一个WaitForIt的struct,这个没有任何用处只需要等待一定的时间返回成功即可。

#[derive(Debug)]
struct WaitFroIt {
    message: String,
    until: DateTime<Utc>,
    polls: u64,
}
impl WaitForIt {
    fn new(message: String, delay: Duration) -> Self {
        WaitForIt {
            message: message,
            polls: 0,
            until: Utc::now() + delay,
        }
    }
}

为WaitForIt实现Future

impl Future for WaitForIt {
    type Item = String;
    type Error = Box<Error>;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let now = Utc::now();
        if self.until < now {
            Ok(Async::Ready(format!("{} after {} polls", self.message, self.polls)))
        }else {
            self. polls += 1;
            println!("not ready yet --> {:?}", self);
            Ok(Async::NotReady)
        }
    }
}

主要需要关注的是fn poll(&mut self) -> Poll<Self::Item, Self::Error>,它返回一个Poll<T,E>,当计算未完成时返回的是Async::NotReady 当计算完成时返回Async::Ready

main函数

fn main() {
    let mut reactor = Core::new().unwrap();

    let wfi_1 = WaitForIt::new("I'm done:".to_owned(), Duration::seconds(1));
    println!("wfi_1 == {:?}", wfi_1);

    let ret = reactor.run(wfi_1).unwrap();
    println!("ret == {:?}", ret);
}

执行:

Running `target/debug/tst_fut_create`
wfi_1 == WaitForIt { message: "I\'m done:", until: 2017-11-07T16:07:06.382232234Z, polls: 0 }
not ready yet --> WaitForIt { message: "I\'m done:", until: 2017-11-07T16:07:06.382232234Z, polls: 1 }

对于reactor来说,它并不会去轮训已经暂停的函数,除非被暂停的函数被启动。在上面的例子中,reactor调用poll的时候,会返回一个Async::NotReady,因此reactor会暂停我们的函数,所以在等待的这段时间,reactor并不会消耗cpu。

如果需要唤醒reactor进行轮询需要使用

futures::task::current().notify()

通知reactor进行轮询

impl Future for WaitForIt {
    type Item = String;
    type Error = Box<Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let now = Utc::now();
        if self.until < now {
            Ok(Async::Ready(
                format!("{} after {} polls!", self.message, self.polls),
            ))
        } else {
            self.polls += 1;

            println!("not ready yet --> {:?}", self);
            futures::task::current().notify();
            Ok(Async::NotReady)
        }
    }
}

对于reactor来说可以同时执行多个future,当某个future被暂停的时候,可以执行其他的future,这里使用join实现这个功能

fn main(){
    let wfi_1 = WaitForIt::new("I'm done: ".to_owned(), Duration::seconds(1));
	println!("wfi_1 == {:?}", wfi_1);
	let wfi_2 = WaitForIt::new("I'm done too:".to_owned(), Duration::seconds(1));
	println!("wfi_2 == {:?}", wfi_2);
    let v = vec![wfi_1, wfi_2];
    let sel = join_all(v);
    let mut reactor = Core::new().unwrap();
    let ret = reactor.run(sel).unwrap();
    println!("ret == {:?}", ret);
}

对于select_all 方法,当第一个任务完成的时候就返回,这个特性特别适合用来实现超时.

fn main() {
    let mut reactor = Core::new().unwrap();

    let wfi_1 = WaitForIt::new("I'm done:".to_owned(), Duration::seconds(1));
    println!("wfi_1 == {:?}", wfi_1);
    let wfi_2 = WaitForIt::new("I'm done too:".to_owned(), Duration::seconds(2));
    println!("wfi_2 == {:?}", wfi_2);

    let v = vec![wfi_1, wfi_2];

    let sel = select_all(v);

    let ret = reactor.run(sel).unwrap();
    println!("ret == {:?}", ret);
}
Future 示例

这个例子更加贴近实际应用场景,例如异步IO,当数据准备好后通知reactor的future进行处理。

实现WaitInAnotherThread 结构体

pub struct WaitInAnotherThread {
    end_time: DateTime<Utc>,
    running: bool,
}
impl WaitInAnotherThread {
     pub fn new(how_long: Duration) -> WaitInAnotherThread {
        WaitInAnotherThread {
            end_time: Utc::now() + how_long,
            running: false,
        }
     }    
     fn run(&mut self, task: task::Task) {
        let lend = self.end_time;
        thread::spawn(move || {
            while Utc::now() < lend {
                let delta_sec = lend.timestamp() - Utc::now().timestamp();
           		if delta_sec > 0 {
                	thread::sleep(::std::time::Duration::from_secs(delta_sec as u64));
            	}
                task.notify();
            }
            println!("the time has come == {:?}!", lend);
        });
    }
}
impl Future for WaitInAnotherThread {
    type Item = ();
    type Error = Box<Error>;
    
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if Utc::now() < self.end_time {
            println!("not ready yet! parking the task.");

            if !self.running {
                println!("side thread not running! starting now!");
                self.run(task::current());
                self.running = true;
            }
            Ok(Async::NotReady)
        } else {
            println!("ready! the task will complete.");
            Ok(Async::Ready(()))
        }
    }
 
}
fn main() {
    let mut reactor = Core::new().unwrap();

    let wiat = WaitInAnotherThread::new(Duration::seconds(3));
    println!("wait future started");
    let ret = reactor.run(wiat).unwrap();
    println!("wait future completed. ret == {:?}", ret);
}