为什么Future::select首先选择睡眠时间较长的未来?
我试图理解:在这个例子中,延迟时间较长的未来首先返回 当我阅读它的例子时,我会产生认知失调。作者写道:为什么Future::select首先选择睡眠时间较长的未来?,select,rust,future,Select,Rust,Future,我试图理解:在这个例子中,延迟时间较长的未来首先返回 当我阅读它的例子时,我会产生认知失调。作者写道: select函数运行两个(如果是select\u all),并返回即将完成的第一个期货。这对于实现超时非常有用 似乎我不明白select的意思 extern crate futures; // v0.1 (old) extern crate tokio_core; use std::thread; use std::time::Duration; use futures::{Async, F
select
函数运行两个(如果是select\u all
),并返回即将完成的第一个期货。这对于实现超时非常有用
似乎我不明白select
的意思
extern crate futures; // v0.1 (old)
extern crate tokio_core;
use std::thread;
use std::time::Duration;
use futures::{Async, Future};
use tokio_core::reactor::Core;
struct Timeout {
time: u32,
}
impl Timeout {
fn new(period: u32) -> Timeout {
Timeout { time: period }
}
}
impl Future for Timeout {
type Item = u32;
type Error = String;
fn poll(&mut self) -> Result<Async<u32>, Self::Error> {
thread::sleep(Duration::from_secs(self.time as u64));
println!("Timeout is done with time {}.", self.time);
Ok(Async::Ready(self.time))
}
}
fn main() {
let mut reactor = Core::new().unwrap();
let time_out1 = Timeout::new(5);
let time_out2 = Timeout::new(1);
let task = time_out1.select(time_out2);
let mut reactor = Core::new().unwrap();
reactor.run(task);
}
extern板条箱期货;//v0.1(旧版)
外部板条箱东京大学核心;
使用std::线程;
使用std::time::Duration;
使用未来:{Async,Future};
使用tokio_堆芯::反应堆::堆芯;
结构超时{
时间:u32,,
}
impl超时{
fn新建(时段:u32)->超时{
超时{time:period}
}
}
impl未来超时{
项目类型=u32;
类型错误=字符串;
fn轮询(&mut self)->结果{
线程::睡眠(持续时间::from_secs(self.time为u64));
println!(“超时是用时间{}完成的,self.time);
Ok(异步::就绪(self.time))
}
}
fn main(){
让mut reactor=Core::new().unwrap();
let time_out 1=超时::新建(5);
let time_out 2=超时::新建(1);
让task=time\u out1.选择(time\u out2);
让mut reactor=Core::new().unwrap();
反应堆运行(任务);
}
我需要以较小的时间延迟处理早期的未来,然后以更长的时间延迟处理未来。我该怎么做?TL;DR:使用东京:时间
如果有一件事需要做的话:永远不要在异步操作中执行阻塞或长时间运行的操作
如果需要超时,请使用中的某些内容,例如或:
有什么问题吗?
要理解你为什么会有这样的行为,你必须从高层次上理解未来的实现
当您调用run
时,会有一个循环调用poll
,对将来传递的数据进行查询。它循环直到未来返回成功或失败,否则未来还没有完成
您的poll
实现将此循环“锁定”5秒钟,因为没有任何东西可以中断对sleep
的调用。当睡眠结束的时候,未来已经准备好了,因此未来是被选择的
异步超时的实现在概念上是通过每次轮询时检查时钟来工作的,比如说是否经过了足够的时间
最大的区别是,当一个未来还没有准备好时,另一个未来可以被检查。这就是select
所做的
戏剧性的重演:
基于睡眠的计时器
核心:嘿选择
,准备好出发了吗
选择:嘿未来1
,你准备好出发了吗
未来1:保持秒[5秒通过…]nnnnd。对!
简单的基于异步的计时器
核心:嘿选择
,准备好出发了吗
选择:嘿未来1
,你准备好出发了吗
未来1:检查表号
选择:嘿未来2
,你准备好出发了吗
未来2:检查表号
核心:嘿选择
,准备好出发了吗
[…投票继续…]
[…1秒通过…]
核心:嘿选择
,准备好出发了吗
选择:嘿未来1
,你准备好出发了吗
未来1:检查表号
选择:嘿未来2
,你准备好出发了吗
未来2:检查手表是
这个简单的实现反复轮询未来,直到它们全部完成。这不是最有效的,也不是大多数遗嘱执行人所做的
有关此类执行器的实现,请参阅
智能异步定时器
核心:嘿选择
,准备好出发了吗
选择:嘿未来1
,你准备好出发了吗
未来1:没有,但有什么变化我会打电话给你
选择:嘿未来2
,你准备好出发了吗
未来2:没有,但有什么变化我会打电话给你
[…核心停止轮询…]
[…1秒通过…]
未来2:嘿,核心,有些事情改变了
核心:嘿选择
,准备好出发了吗
选择:嘿未来1
,你准备好出发了吗
未来1:检查表号
选择:嘿未来2
,你准备好出发了吗
未来2:检查手表是
这种更高效的实现在轮询每个未来时为其提供一个唤醒器。当一个未来还没有准备好时,它会把这个唤醒器保存起来以备将来使用。当某些事情发生变化时,唤醒器通知执行器的核心,现在是重新检查未来的好时机。这允许执行者不执行有效的繁忙等待
通用解决方案
当您有一个阻塞或长时间运行的操作时,适当的做法是将该工作移出异步循环。有关详细信息和示例,请参见。是否可以使用
CpuPool
中的CpuPool
使用futures\u CpuPool::CpuPool
?Sergey我不确定是否理解您的问题,但是我试图回答。基于异步定时器的检查率是否会影响程序的性能?如果是,我如何配置它,如果不是,为什么?@Renkai
use futures::future::{self, Either}; // 0.3.1
use std::time::Duration;
use tokio::time; // 0.2.9
#[tokio::main]
async fn main() {
let time_out1 = time::delay_for(Duration::from_secs(5));
let time_out2 = time::delay_for(Duration::from_secs(1));
match future::select(time_out1, time_out2).await {
Either::Left(_) => println!("Timer 1 finished"),
Either::Right(_) => println!("Timer 2 finished"),
}
}