介绍
简单来讲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);
}