How can i Improve the efficiency of the timer?

use std::{future::Future, task::Poll, time::Duration};

use tokio::{sync::mpsc, time::Instant};

trait MyTask {
    fn run(&self) -> String;
}

#[derive(Clone)]
struct AutoTask {
    name: String,
    date: Instant,
    cycle: Duration,
    run: fn() -> String,
}

fn complex_fn() -> String {
    "String_complex".into()
}
impl AutoTask {
    fn next(&mut self) {
        self.date += self.cycle;
    }
}

impl Future for AutoTask {
    type Output = AutoTask;

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
        if Instant::now() >= self.date {
            println!("start {}", self.name);
            //Poll::Ready(self.name.clone())
            let r = (self.run)();
            println!("{r}");
            Poll::Ready(self.clone())
        } else {
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }
}

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);

    let arc_task = AutoTask {
        name: "task1".into(),
        date: Instant::now() + Duration::from_secs(3),
        cycle: Duration::from_secs(3),
        run: complex_fn,
    };

    let t1 = tx.clone();
    let _ = tokio::spawn(async move {
        let future = arc_task.await;
        let _ = t1.send(future).await;
    });

    //BUG: 反复clone,明显低效率方式*********************************
    while let Some(mut message) = rx.recv().await {
        let t2 = tx.clone();
        let _ = tokio::spawn(async move {
            message.next();
            let future = message.await;
            let _ = t2.send(future).await;
        });
    }
}


:grinning: :grinning: :grinning:

This is incredibly inefficient and will consume an entire CPU core at 100%. It is basically the same as this:

while Instant::now() < self.date {
    // do nothing
}

If you want to efficiently sleep, there are these options:

  1. Use the timer provided by Tokio in tokio::time.
  2. Use an AsyncFd with a timerfd to sleep. This timer can be more precise than tokio::time.
  3. Spawn a dedicated thread for handling the timers. It will keep track of the list of pending timers can call .wake() when a timer should wake up.
2 Likes