How do I spawn many cancellable timers using Tokio?
如何使用Tokio实现固定数量的计时器,这些计时器在线程之间定期重置和取消?当计时器到期时,将执行回调。
我想要的是类似于Go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package main import ( "fmt" "time" ) func main() { t := time.AfterFunc(time.Hour, func() { // happens every 2 seconds with 1 second delay fmt.Println("fired") }) for { t.Reset(time.Second) time.Sleep(time.Second * 2) } } |
我发现唯一实现(足够)相似的API的板条箱是计时器,它通过产生2个线程以非常幼稚的方式实现。当经常重置计时器时,这很快变得令人望而却步。
显而易见的答案是使用Tokio,问题是如何优雅地做到这一点。
一种选择是,每当更新计时器时,都会生成一个新的绿色线程,并使用一个原子通过取消对该原子的回调执行条件来取消前一个计时器,例如伪锈:
1 2 3 4 5 6 7 8 9 10 11 12 13 | tokio::run({ // for every timer spawn with a new"cancel" atomic tokio::spawn({ Delay::new(Instant::now() + Duration::from_millis(1000)) .map_err(|e| panic!("timer failed; err={:?}", e)) .and_then(|_| { if !cancelled.load(Ordering::Acquire) { println!("fired"); } Ok(()) }) }) }) |
问题是我为已经取消的计时器保持状态,可能要持续几分钟。另外,它看起来并不优雅。
除了
尚不清楚如何在多线程应用程序中使用此库,即:
The return value represents the insertion and is used at an argument to remove and reset. Note that Key is token and is reused once value is removed from the queue either by calling poll after when is reached or by calling remove. At this point, the caller must take care to not use the returned Key again as it may reference a different item in the queue.
这将在任务通过其键取消计时器和使用
您可以将futures-rs中的
作为第二个未来,我们可以使用来自
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | use futures::sync::oneshot; use futures::*; use std::thread; use std::time::{Duration, Instant}; use tokio::timer::Delay; fn main() { let (interrupter, interrupt_handler) = oneshot::channel::<()>(); //signal to cancel delayed call thread::spawn(move || { thread::sleep(Duration::from_millis(500)); //increase this value more than 1000ms to see is delayed call is working or not. interrupter .send(()) .expect("Not able to cancel delayed future"); }); let delayed = Delay::new(Instant::now() + Duration::from_millis(1000)) .map_err(|e| panic!("timer failed; err={:?}", e)) .and_then(|_| { println!("Delayed Call Executed!"); Ok(()) }); tokio::run(delayed.select(interrupt_handler).then(|_| Ok(()))); } |
操场