I try to use the indicatif crate to show several progress bars of sub-tasks together with one progress bar counting all finished tasks. Here is my code:
# Cargo.toml
[dependencies]
indicatif = "0.15.0"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
//! main.rs
use std::time::Duration;
use futures::{StreamExt, stream::futures_unordered::FuturesUnordered};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let m = MultiProgress::new();
let sty = ProgressStyle::default_bar()
.template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
.progress_chars("##-");
let total_pb = m.add(ProgressBar::new(3));
total_pb.set_style(sty.clone());
let mut futs = FuturesUnordered::new();
let durations = [15u64, 8, 3];
let mut pb_cnt = 0usize;
for &duration in durations.iter() {
let pb = m.insert(pb_cnt, ProgressBar::new(256));
pb_cnt += 1;
pb.set_style(sty.clone());
let total_pb = total_pb.clone();
let task = tokio::spawn(async move {
for i in 0i32..256 {
pb.set_message(&format!("item #{}", i + 1));
pb.inc(1);
tokio::time::sleep(Duration::from_millis(duration)).await;
}
pb.finish_with_message("done");
total_pb.inc(1);
});
futs.push(task);
}
while let Some(result) = futs.next().await {
result?;
}
total_pb.finish_with_message("done");
m.join()?;
// tokio::task::spawn_blocking(move || m.join().unwrap() ).await.unwrap();
Ok(())
}
total_pb
is the bar counting all finished tasks.
The problem is that no progress bars appear on the console until all work has finished already, only showing me their final states. I tried to follow suggestions in this issue and this issue, but there are a couple problems:
- I tried to insert
let m = tokio::task::spawn_blocking(move || m.join().unwrap());
as in the code above but it doesn't work. total_pb
won't finish until all tasks finish, which meansm.join()
cannot be called right after each spawned task as an synchronization as suggested in the first issue.