这是indexloc提供的服务,不要输入任何密码
Skip to content

maitake timer should support rescheduling sleeps #556

@hawkw

Description

@hawkw

Currently, using maitake's time module, if you want to implement a repeating periodic action on a scheduled interval, you would write something like this:

let interval = maitake::time::Duration::from_secs(5); // or whatever
loop {
    maitake::time::sleep(interval).await;
    do_the_thing().await;
}

This works fine, but it has a bit of extra overhead. Creating a new sleep future locks the timer wheel, so we have to do that every time we start waiting again. When the sleep completes, it's removed from the wheel.

To make the periodic timer use case more efficient, Tokio provides the tokio::time::Interval type (and the tokio::time::{interval, interval_at} functions). This is similar to a sleep, except that instead of removing the entry from the timer wheel when it completes, the wheel automatically reschedules it to fire again the next time the period has elapsed. This avoids having to re-lock the wheel the next time the code that implements a periodic action wants to create a new sleep. The API for this allows the user code to wait on a tick() future returned by the Interval type, rather than consuming it:

let mut interval = maitake::time::interval(Duration::from_secs(5)); // or whatever
loop {
    interval.tick().await;
    do_the_thing().await;
}

It_also_ makes the period a bit more accurate, since the next period starts as soon as the timer wheel entry is woken, rather than after the periodic action runs and the periodic task wishes to wait for the next period to elapse. In the above examples, if do_the_thing() took a long time to complete, or sometimes yields for a long time waiting on some external wakeup, the sleep based approach is actually running the action exactly every 5 seconds, but every 5 + (how long it takes for do_the_thing() to return) seconds. This makes the period a bit sloppier than it would be if the timer was automatically rescheduled as soon as the timer wheel wakes it up.

If we supported the internal mechanisms to re-schedule a (potentially) completed timer wheel entry, we would also be able to implement a function for resetting a Sleep to fire at an arbitrary duration, like tokio::time::Sleep::reset(). While this interface wouldn't be a replacement for an automatically-reset Interval (as it would still lock the wheel every time the timer wheel entry is reset through the Sleep type), it's a nice interface to have for some use cases, like select!ing over a sleep and a bunch of other futures in a loop. Sometimes, user code may wish to reset the sleep to be selected over in another iteration of a loop if a different future completed first, such as to reset a timeout. An API for this is a bit less annoying than one where you have to replace the Sleep with a whole new one. And, it's a bit more efficient, since replacing a Sleep that hasn't completed with a new one locks the wheel twice --- once to create the new Sleep and again to drop the old one. The reset() API never drops a sleep, so it's only one lock.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions