如何解决如何使用 indicatif 在异步 Rust 中显示总计数器栏?
我尝试使用“indicatif”包来显示子任务的多个进度条以及一个计算所有完成任务的进度条。我的代码是异步的并使用 tokio。下面是一个例子:
cargo.toml
[package]
name = "test-project"
version = "0.1.0"
edition = "2018"
# See more keys and their deFinitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
indicatif = "0.15.0"
tokio = { version = "1",features = ["full"] }
futures = "0.3"
src/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
是统计所有已完成任务的条形。
问题是在所有工作都完成之前,控制台上不会出现任何进度条,只向我显示它们的最终状态。我尝试遵循 issue1 和 issue2 中的建议,但有两个问题:
- 我尝试像上面的代码一样插入
let m = tokio::task::spawn_blocking(move || m.join().unwrap());
,但它不起作用; -
total_pb
在所有任务完成之前不会完成,这意味着m.join()
不能在每个生成的任务之后立即调用作为问题 1 中建议的同步。
如果相关,我使用的是 Windows 10。
解决方法
有不同的解决方案,您需要在活动阻塞线程上调用 m.join()
。要么在主线程中执行此操作,因此您需要移动您的:
while let Some(result) = futs.next().await {
result?;
}
其他地方,比如生成一个任务。
或者你生成一个阻塞线程并在最后等待它(可能是最好的)。所以就这样做:
let handle_m = tokio::task::spawn_blocking(move || m.join().unwrap()); // add this line
while let Some(result) = futs.next().await {
result?;
}
total_pb.finish_with_message("done");
handle_m.await?; // don't forget to await your handle
请注意,与尝试 #1 不同的是,您必须在等待结果之前生成阻塞线程...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。