rust - 什么是获得解决未来需要多长时间的干净方法?
问题描述
我正在与 Tokio 一起做一些 UDP 的事情。
我想记录我的 UDP 探测未来解决的时间量。我想出了以下函数,time_future()
来包装未来并给我结果和持续时间。这个函数看起来很幼稚,我认为 Rust 有能力更清晰地表达这个概念。
我的工作代码(游乐场):
extern crate futures; // 0.1.25
extern crate tokio; // 0.1.11
use std::time::{Duration, Instant};
use futures::future::{lazy, ok};
use futures::Future;
use tokio::runtime::current_thread::Runtime;
use tokio::timer::Delay;
struct TimedFutureResult<T, E> {
elapsed: Duration,
result: Result<T, E>,
}
impl<T, E> TimedFutureResult<T, E> {
pub fn elapsed_ms(&self) -> i64 {
return (self.elapsed.as_secs() * 1000 + (self.elapsed.subsec_nanos() / 1000000) as u64)
as i64;
}
}
fn time_future<F: Future>(f: F) -> impl Future<Item = TimedFutureResult<F::Item, F::Error>> {
lazy(|| {
let start = Instant::now();
f.then(move |result| {
ok::<TimedFutureResult<F::Item, F::Error>, ()>(TimedFutureResult {
elapsed: start.elapsed(),
result: result,
})
})
})
}
fn main() {
let when = Instant::now() + Duration::from_millis(100);
let f = time_future(Delay::new(when)).then(|r| match r {
Ok(r) => {
println!("resolved in {}ms", r.elapsed_ms());
r.result
}
_ => unreachable!(),
});
let mut runtime = Runtime::new().unwrap();
runtime.block_on(f).unwrap();
}
我该如何改进这一点并使其更惯用?我可以以某种方式让界面与inspect()
or类似地工作then()
吗?
Delay::new(when)
.timed(|res, elapsed| println!("{}ms!", elapsed))
.and_then(...);
我尝试创建一个Timed
trait 并实现它,Future
但我对自己的实现方式完全没有信心。这些类型真的让我陷入了循环。
我至少在吠叫正确的树吗?
解决方案
编写未来的行为很容易,添加可链接方法与如何向迭代器中添加新方法中显示的技术相同?.
唯一真正棘手的方面是决定时间的开始时间——是创建未来还是首次轮询?
我选择在第一次轮询时使用,因为这似乎更有用:
extern crate futures; // 0.1.25
extern crate tokio; // 0.1.11
use std::time::{Duration, Instant};
use futures::{try_ready, Async, Future, Poll};
use tokio::{runtime::current_thread::Runtime, timer::Delay};
struct Timed<Fut, F>
where
Fut: Future,
F: FnMut(&Fut::Item, Duration),
{
inner: Fut,
f: F,
start: Option<Instant>,
}
impl<Fut, F> Future for Timed<Fut, F>
where
Fut: Future,
F: FnMut(&Fut::Item, Duration),
{
type Item = Fut::Item;
type Error = Fut::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let start = self.start.get_or_insert_with(Instant::now);
let v = try_ready!(self.inner.poll());
let elapsed = start.elapsed();
(self.f)(&v, elapsed);
Ok(Async::Ready(v))
}
}
trait TimedExt: Sized + Future {
fn timed<F>(self, f: F) -> Timed<Self, F>
where
F: FnMut(&Self::Item, Duration),
{
Timed {
inner: self,
f,
start: None,
}
}
}
impl<F: Future> TimedExt for F {}
fn main() {
let when = Instant::now() + Duration::from_millis(100);
let f = Delay::new(when).timed(|res, elapsed| println!("{:?} elapsed, got {:?}", elapsed, res));
let mut runtime = Runtime::new().unwrap();
runtime.block_on(f).unwrap();
}
推荐阅读
- laravel - Laravel 工厂问题
- arrays - 多次复印多张纸
- unreal-engine4 - 虚幻引擎 SImage ColorAndOpacity 不起作用
- python - Django查询集字段查找对象列表
- c++ - 在其他 Linux 主机上运行二进制文件时出现符号查找错误,而所有共享库均已成功解析
- spring - 为什么docker中的应用程序在eureka中注册像一些哈希而不是IP地址
- c++ - 为什么 C++17 会引入 std::aligned_alloc?
- php - 如何将命令的输出作为另一个输入?
- python - 使用python从网站下载书籍
- laravel - 在新的 Laravel/Livewire 安装中,得到一个 RuntimeException :尚未设置外观根