rust - Tokio 任务在完成前退出
问题描述
下面的程序应该从多个线程定期打印,但tokio::time::sleep
没有按我预期的那样工作:
use tokio::prelude::*; //0.3.4
use tokio::runtime::Builder;
use tokio::time::Duration;
fn main() {
let rt = Builder::new_multi_thread()
.enable_all()
.thread_stack_size(3 * 1024 * 1024)
.build()
.unwrap();
rt.block_on(async {
tokio::spawn(print_thread(1));
tokio::spawn(print_thread(2));
tokio::spawn(print_thread(3));
tokio::spawn(print_thread(4));
});
}
async fn print_thread(thread_num: usize) {
tokio::spawn(async move {
println!("thread{}-start", thread_num);
loop {
tokio::time::sleep(Duration::from_millis(1000)).await;
println!("thread{}-running", thread_num);
}
println!("thread{}-start", thread_num);
});
}
它的输出是
$cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.64s
Running `target/debug/time_test`
thread1-start
thread2-start
thread3-start
thread4-start
$
我希望看到消息threadN-running
,但没有输出。我不知道为什么程序突然退出。有人可以告诉我原因吗?
我的Cargo.toml
样子是这样的:
[package]
name = "time_test"
version = "0.1.0"
edition = "2018"
[dependencies]
tokio = { version = "0.3", features = ["full"] }
另外,我的货物版本是:
$ cargo --version
cargo 1.48.0 (65cbdd2dc 2020-10-14)
解决方案
外async
块:
rt.block_on(async { ... })
不加入生成的未来,所以它在生成后立即结束。在内部有时间和之前,这结束了block_on
和。任务在完成执行之前被杀死。main
task
sleep
println!
您可以通过将 包裹block_on
在一个永无止境的循环中来解决这个问题:
loop {
rt.block_on(async {
tokio::spawn(print_thread(1));
tokio::spawn(print_thread(2));
tokio::spawn(print_thread(3));
tokio::spawn(print_thread(4));
});
}
现在,tokio 执行器拥有生成 , 并将消息打印到控制台所需的所有tasks
时间sleep
。但是,这loop
将是昂贵的 cpu 明智的。另一种选择是使用std::future::pending
自 Rust 1.48 起稳定的。这将创建一个永远不会解决的未来,代表一个永远不会完成的计算:
rt.block_on(async {
...
});
std::future::pending().await;
unreachable!();
此外,正如@AlexLarionov 所提到的,您实际上是在产卵task
两次:
// 1st task
tokio::spawn(print_thread(1))
// 2nd task
async fn print_thread(thread_num: usize) {
tokio::spawn(async move { ... });
}
第二次生成是不必要的,您的print_thread
功能可以简化为以下内容:
async fn print_thread(thread_num: usize) {
println!("thread{}-start", thread_num);
loop {
tokio::time::sleep(Duration::from_millis(1000)).await;
println!("thread{}-running", thread_num);
}
// Note that this is unreachable
println!("thread{}-start", thread_num);
}
请注意,对于用例tokio::time::sleep
可能不是最佳选择。要按计划定期运行某些内容,您可以使用tokoi::time::interval
:
async fn print_thread(thread_num: usize) {
println!("thread{}-start", thread_num);
let mut interval = tokio::time::interval(Duration::from_millis(100));
loop {
interval.tick().await;
println!("thread{}-running", thread_num);
}
}
推荐阅读
- laravel - 如何修复“GET css/app.css net::ERR_ABORTED 404(未找到)”?
- xamarin - 未找到 JetBrains Rider 的 Xamarin SDK
- android - 我无法在未解决的参考中找出错误
- razor - 如何用foreach编写复选框?
- regex - 用正则表达式替换进行它的单词
- python - MySQL游标使用最后一个游标更新所有列
- android - 为什么 contentResolver.query() 返回 null?
- vue.js - 无法使用 JsPdf 导出 pdf
- python - 如何使用 argparse 以 xml 格式传递参数?
- python - 将 $45,000,000.00 (str) 转换为浮点数