如何使用Tokio在每个固定时间间隔内触发一个函数?

19
在 Node.js 中,我可以设置某个事件触发的时间间隔,
function intervalFunc() {
  console.log('whelp, triggered again!');
}

setInterval(intervalFunc, 1500);

不过,Tokio的interval接口略微复杂一些。它似乎与时间间隔的更为字面化的定义有关,而不是在时间间隔内调用函数,它只是简单地暂停线程,直到时间过去(使用.await)。

Tokio中是否有一个原语可以每隔x秒钟调用一个函数或类似的东西?如果没有,是否出现了一种惯用语来解决这个问题?

我只需要在Tokio的事件循环中定期运行一个功能... 我也不关心其他线程。只是一个函数在运行。

2个回答

33

生成Tokio任务以永久执行某些操作:

use std::time::Duration;
use tokio::{task, time}; // 1.3.0

#[tokio::main]
async fn main() {
    let forever = task::spawn(async {
        let mut interval = time::interval(Duration::from_millis(10));

        loop {
            interval.tick().await;
            do_something().await;
        }
    });

    forever.await;
}
你还可以使用 tokio::time::interval 创建一个可重复触发的值。在 stream::unfold 的主体内执行触发并调用你的函数以创建一个流:
use futures::{stream, StreamExt}; // 0.3.13
use std::time::{Duration, Instant};
use tokio::time; // 1.3.0

#[tokio::main]
async fn main() {
    let interval = time::interval(Duration::from_millis(10));

    let forever = stream::unfold(interval, |mut interval| async {
        interval.tick().await;
        do_something().await;
        Some(((), interval))
    });

    let now = Instant::now();
    forever.for_each(|_| async {}).await;
}

async fn do_something() {
    eprintln!("do_something");
}

另请参阅:


这真是令人困惑...你不能用.repeat来做这个吗? - Evan Carroll
repeat函数的说明是:创建一个流,该流会重复生成相同的项,但这并不是你想要的。 - Shepmaster
好吧,看起来我可以创建一个函数指针流,它会在间隔时间内睡眠并运行它们,或者创建一组函数指针和时间间隔流并将它们合并并等待执行。 - Evan Carroll
1
使用forever.await代替timeout - Shepmaster
1
如果我们将这两个东西都无限循环而不是循环10次,并且放弃计算经过的时间,这样我们可以更清楚地演示它们。这些只是一些要点(我已经投票并标记了这个问题)。我还提出了一个后续问题,https://stackoverflow.com/q/66898839/124486 - Evan Carroll
显示剩余3条评论

2

我仍然是一个Rust/Tokio的初学者,但我发现这个解决方案对我很有帮助:

use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;

#[tokio::main]
async fn main() {
    let mut stream = IntervalStream::new(time::interval(Duration::from_secs(1)));

    while let Some(_ts) = stream.next().await {
        println!("whelp, triggered again!");
    }
}

请注意,_ts保存了执行时间戳。

尽管这是一个不太普适的解决方案,但它更适用于我们代码库中大多数时间重复流的情况。 - sukhmel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接