Skip to content

Instantly share code, notes, and snippets.

@Porges
Created February 21, 2022 02:06
Show Gist options
  • Save Porges/72dc5e2fdac91a511da5f1d7cf354611 to your computer and use it in GitHub Desktop.
Save Porges/72dc5e2fdac91a511da5f1d7cf354611 to your computer and use it in GitHub Desktop.
use futures_util::Future;
use tokio::time::{self, Duration, Instant, MissedTickBehavior};
pub struct Pacer {
period: Duration,
total_duration: Duration,
behavior: MissedTickBehavior,
}
impl Pacer {
pub fn new(period: Duration, total_duration: Duration, behavior: MissedTickBehavior) -> Self {
Self {
period,
total_duration,
behavior,
}
}
pub async fn run<F, Fut, E>(&self, mut task: F) -> Result<(), E>
where
F: FnMut() -> Fut,
Fut: Future<Output = Result<(), E>>,
{
let mut interval = time::interval(self.period);
interval.set_missed_tick_behavior(self.behavior);
let end = Instant::now() + self.total_duration;
loop {
task().await?;
if Instant::now() >= end {
return Ok(());
}
interval.tick().await;
}
}
}
#[tokio::main]
async fn main() {
struct Task {
last_invoked: Option<Instant>,
}
impl Task {
fn new() -> Self {
Self { last_invoked: None }
}
fn tick(&mut self) -> impl Future<Output = anyhow::Result<()>> {
let now = Instant::now();
let since_last = self.last_invoked.map(|i| now.duration_since(i));
println!(".{:?}", since_last);
self.last_invoked = Some(now);
// pretend this method would do its own .await
async { Ok(()) }
}
}
let pacer = Pacer::new(
Duration::from_millis(1),
Duration::from_millis(50),
MissedTickBehavior::Delay,
);
let mut task = Task::new();
let started = Instant::now();
let _ = pacer
.run(move || task.tick())
.await
.expect("Task should not produce an error");
println!("total elapsed: {:?}", started.elapsed());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment