如何产生重复任务并等待其首次执行?
How to spawn a repeating task and await its first execution?
在 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;
});
}
这行得通,但我有一些疑问
- 在这里
task::spawn
两次是不是浪费资源?有什么办法只能做一次吗?
- 函数一结束就丢弃外面的
task::spawn
是不是错误?它是否会无限期地获得 运行,即使它不再被跟踪,只是被解雇并被遗忘?
回答你的两个问题:
- 不必担心产生太多任务:在您的平均硬件上,您应该能够每秒产生 100,000 个任务。但是,在这种情况下是不必要的,因为:
- 如果任务被删除,它们就会“分离”,因此它们内部的未来将继续由您的运行时轮询。这也意味着您不需要
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;
}
});
}
在 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;
});
}
这行得通,但我有一些疑问
- 在这里
task::spawn
两次是不是浪费资源?有什么办法只能做一次吗? - 函数一结束就丢弃外面的
task::spawn
是不是错误?它是否会无限期地获得 运行,即使它不再被跟踪,只是被解雇并被遗忘?
回答你的两个问题:
- 不必担心产生太多任务:在您的平均硬件上,您应该能够每秒产生 100,000 个任务。但是,在这种情况下是不必要的,因为:
- 如果任务被删除,它们就会“分离”,因此它们内部的未来将继续由您的运行时轮询。这也意味着您不需要
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;
}
});
}