睡眠在未来::民意调查



我正在尝试为来自crossterm机箱的输入创建一个未来的轮询,据我所知,该机箱不提供异步API。

起初,我试着做以下事情:


use crossterm::event::poll as crossterm_poll;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use tokio::time::{sleep, timeout};
struct Polled {}
impl Polled {
pub fn new() -> Polled {
Polled {}
}
}
impl Future for Polled {
type Output = bool;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// If there are events pending, it returns "Ok(true)", else it returns instantly
let poll_status = crossterm_poll(Duration::from_secs(0));
if poll_status.is_ok() && poll_status.unwrap() {
return Poll::Ready(true);
}
Poll::Pending
}
}
pub async fn poll(d: Duration) -> Result<bool, ()> {
let polled = Polled::new();
match timeout(d, polled).await {
Ok(b) => Ok(b),
Err(_) => Err(()),
}
}

从技术上讲,它是有效的,但不幸的是,程序开始一直使用100%的CPU,因为执行器总是试图轮询未来,以防出现新的情况。因此,我想添加一些异步等效的睡眠,这将推迟执行器下次尝试轮询Future的时间,所以我尝试添加以下内容(就在返回Poll::Pending之前(,这显然不起作用,因为sleep_future::poll()只返回Pending:

let mut sleep_future = sleep(Duration::from_millis(50));
tokio::pin!(sleep_future);
sleep_future.poll(cx);
cx.waker().wake_by_ref();

poll不是async这一事实禁止使用async函数,我开始怀疑我想做的事情是否真的可行,或者我是否没有以错误的方式解决我的第一个问题。

找到一种方法让async睡眠是一个好方法吗?如果不是,那是什么?我是不是在异步范例中遗漏了什么?或者,如果机箱没有为您提供必要的工具,那么有时就不可能将一些同步逻辑封装到Future中吗?

无论如何,提前谢谢!

编辑:我找到了一种使用async块做我想做的事情的方法:


pub async fn poll(d: Duration) -> Result<bool, ()> {
let mdr = async {
loop {
let a = crossterm_poll(Duration::from_secs(0));
if a.is_ok() && a.unwrap() {
break;
}
sleep(Duration::from_millis(50)).await;
}
true
};
match timeout(d, mdr).await {
Ok(b) => Ok(b),
Err(_) => Err(()),
}
}

这是惯用的方法吗?还是我错过了更优雅的东西?

是的,使用async块是组合期货的好方法,就像您的自定义轮询器和tokio的sleep一样。

然而,如果您确实想编写自己的Future,它也调用tokio的sleep,以下是您需要做的不同操作:

  1. 不要立即调用wake_by_ref()——当时间到来时,睡眠未来会处理好这一问题,这就是避免旋转(使用100%CPU(的方法
  2. 当你打算睡觉时(不是每次轮询时(,你必须构造一次sleep()future,然后将其存储在你的future中(这需要pin投影(,并在下次轮询时再次轮询同一future。这就是你如何确保你等待预定的时间,而不是更短

异步块通常是获得相同结果的更容易的方法。

最新更新