如何生成重复任务并等待其第一次执行



在JS:中重建setInterval

pub async fn set_interval<T, F>(interval: Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: Future + Send,
{
let forever = task::spawn(async move {
let mut interval = time::interval(interval);
loop {
interval.tick().await;
do_something().await;
}
});
forever.await;
}

这是可行的,但我希望它能够.await,直到第一次执行结束。

即不做:

do_something().await
set_interval(Duration::from_secs(1), do_something)

我想:

set_interval(Duration::from_secs(1), do_something).await

请注意,这与上面的行为不同,因为它立即运行do_something任务,但这是有意的。

我的解决方案:

pub async fn set_interval<T, F>(interval: Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: Future + Send,
{
do_something().await;

task::spawn(async move {
let forever = task::spawn(async move {
let mut interval = time::interval(interval);
loop {
interval.tick().await;
do_something().await;
}
});
forever.await;
});
}

这是有效的,但我有一些疑问

  1. 这里两次task::spawn是浪费资源吗?有没有办法只做一次
  2. 函数一结束就丢弃外部task::spawn是错误的吗?它会无限期地运行吗,即使它不再被跟踪,只是被解雇和遗忘了

回答您的两个问题:

  1. 不要担心产生太多任务:在你的普通硬件上,你应该能够每秒产生100000个任务。不过,在这种情况下没有必要,因为:
  2. 任务得到"分离的";如果它们被丢弃,那么运行时将继续轮询其中的期货。这也意味着您不需要forever.await

以下似乎有效:

pub async fn set_interval<T, F>(interval: std::time::Duration, do_something: T)
where
T: (Fn() -> F) + Send + Sync + 'static,
F: std::future::Future + Send,
{
// The interval time alignment is decided at construction time. 
// For all calls to be evenly spaced, the interval must be constructed first.
let mut interval = tokio::time::interval(interval);
// The first tick happens without delay.
// Whether to tick before the first do_something or after doesn't matter.
interval.tick().await;

do_something().await;

tokio::task::spawn(async move {
loop {
interval.tick().await;
do_something().await;
}
});
}

游乐场

最新更新