首页 > 解决方案 > 什么是获得解决未来需要多长时间的干净方法?

问题描述

我正在与 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(...);

我尝试创建一个Timedtrait 并实现它,Future但我对自己的实现方式完全没有信心。这些类型真的让我陷入了循环。

我至少在吠叫正确的树吗?

标签: rusttraitstimingrust-tokio

解决方案


编写未来的行为很容易,添加可链接方法与如何向迭代器中添加新方法中显示的技术相同?.

唯一真正棘手的方面是决定时间的开始时间——是创建未来还是首次轮询

我选择在第一次轮询时使用,因为这似乎更有用:

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();
}

推荐阅读