I have two threads:
controller thread (process sink msg): send bool to tick thread using channel.
tick thread: get message from channel and once the sent msg is true, start to wakeup every n seconds.
The duration is let mut interval = tokio::time::interval(Duration::from_secs(5));
=> 5 seconds
The following is my tick thread:
pub async fn tick(
p: ProgressBar,
mut tick_receiver: Receiver<bool>,
sink_sender: Sender<SinkMessage>,
) {
let mut is_playing = false;
let mut interval = tokio::time::interval(Duration::from_secs(5));
// let sleep = time::sleep(Duration::from_secs(1));
let tick_channel_future = async { tick_receiver.recv().await.unwrap() };
// tokio::pin!(sleep);
tokio::pin!(tick_channel_future);
loop {
tokio::select! {
true = &mut tick_channel_future, if !is_playing => {
// println!("{:?}", "----------> getting tick message true");
is_playing = true;
},
_ = interval.tick(), if is_playing => {
println!("in tick {:?} {:?}", p.position(), chrono::Utc::now().to_rfc2822());
// p.inc(1);
},
else => {
is_playing = false;
}
}
}
}
During the startup, there are so many spurious wakeup from the interval tick as shown in the log:
What's the root cause and how to deal with this issue? Thanks in advance!
1 Like
Things seem to work as expected with this code.
use std::time::Duration;
#[tokio::main]
async fn main() {
let mut interval = tokio::time::interval(Duration::from_secs(5));
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
let fut = async { rx.recv().await.unwrap() };
tokio::pin!(fut);
tx.send(true).await.unwrap();
let mut done = false;
loop {
tokio::select! {
true = &mut fut, if !done => {
println!("go");
done = true;
}
_ = interval.tick(), if done => {
println!("{}", chrono::Utc::now().to_rfc2822())
}
}
}
}
are you sure you aren't calling tick
multiple times?
semicoleon:
use std::time::Duration;
#[tokio::main]
async fn main() {
let mut interval = tokio::time::interval(Duration::from_secs(5));
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
let fut = async { rx.recv().await.unwrap() };
tokio::pin!(fut);
tx.send(true).await.unwrap();
let mut done = false;
loop {
tokio::select! {
true = &mut fut, if !done => {
println!("go");
done = true;
}
_ = interval.tick(), if done => {
println!("{}", chrono::Utc::now().to_rfc2822())
}
}
}
}
Thanks for the reply. I'm able to reproduce the issue with the following snippet:
The key is to add the Select::new()
from inquire.
use inquire::Select;
use std::thread;
use std::time::Duration;
use tokio::sync::mpsc::Receiver;
#[tokio::main]
async fn main() {
let (tx, rx) = tokio::sync::mpsc::channel(100);
let _t = tokio::spawn(async move {
tick(rx).await;
});
let b = thread::spawn(move || {
let options = vec![
"Banana",
"Apple",
"Strawberry",
"Grapes",
"Lemon",
"Tangerine",
"Watermelon",
"Orange",
"Pear",
"Avocado",
"Pineapple",
"Banana",
"Apple",
"Strawberry",
"Grapes",
"Lemon",
"Tangerine",
"Watermelon",
"Orange",
"Banana",
"Apple",
"Strawberry",
"Grapes",
"Lemon",
"Tangerine",
"Watermelon",
"Orange",
"Banana",
"Apple",
"Strawberry",
"Grapes",
"Lemon",
"Tangerine",
"Watermelon",
"Orange",
];
let _ans = Select::new("choose a song: ", options).prompt();
tx.blocking_send(true).unwrap();
loop {
thread::sleep(Duration::from_secs(4));
}
});
b.join().unwrap();
}
async fn tick(mut rx: Receiver<bool>) {
let mut interval = tokio::time::interval(Duration::from_secs(5));
let fut = async { rx.recv().await.unwrap() };
tokio::pin!(fut);
let mut done = false;
loop {
tokio::select! {
true = &mut fut, if !done => {
println!("go");
done = true;
}
_ = interval.tick(), if done => {
println!("{}", chrono::Utc::now().to_rfc2822())
}
}
}
}
Try to spend a few more seconds while you are on this interface:
Ahh okay. I'm seeing one "spurious" tick per 5 seconds I wait on the menu. The interval is "catching up" on missed ticks because the default missed_tick_behavior
is MissedTickBehavior::Burst
Adding
interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
gets the behavior you want, at least in this part of the program.
1 Like
WOW, amazing! Thanks a lot.