【问题标题】:failed to run two threads using #[tokio::main] macro无法使用 #[tokio::main] 宏运行两个线程
【发布时间】:2022-11-03 22:20:13
【问题描述】:
我试图了解tokio 运行时是如何工作的,我使用#[tokio::main] 宏创建了两个运行时(故意),第一个应该执行function a(),第二个应该执行function b()。
我假设他们应该永远同时打印"im awake A" 和"im awake B"(因为他们正在调用一个具有循环async_task 的函数),但事实并非如此,它只打印"im awake A".
因为每个运行时都有自己的线程池;为什么它们不并行运行?
use std::thread;
fn main() {
a();
b();
}
#[tokio::main]
async fn a() {
tokio::spawn(async move { async_task("A".to_string()).await });
}
pub async fn async_task(msg: String) {
loop {
thread::sleep(std::time::Duration::from_millis(1000));
println!("im awake {}", msg);
}
}
#[tokio::main]
async fn b() {
tokio::spawn(async move { async_task("B".to_string()).await });
}
【问题讨论】:
标签:
rust
async-await
rust-tokio
【解决方案1】:
#[tokio::main] 扩展为对Runtime::block_on() 的调用,正如其文档中所说(强调我的):
这在当前线程上运行给定的未来,阻塞直到完成,并产生其解析结果。
如果您使用 Runtime::spawn() 代替(并确保不要因为它关闭运行时而放弃运行时),它会从 A 和 B 正确打印:
fn main() {
let _a_runtime = a();
b();
}
fn a() -> tokio::runtime::Runtime {
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.spawn(async { async_task("A".to_string()).await });
runtime
}
#[tokio::main]
async fn b() {
tokio::spawn(async move { async_task("B".to_string()).await });
}
【解决方案2】:
从同步的main 函数调用a(); 将阻塞,直到a() 完成。在此处查看文档:https://docs.rs/tokio/1.2.0/tokio/attr.main.html
#[tokio::main]
async fn main() {
println!("Hello world");
}
不使用 #[tokio::main] 的等效代码
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
println!("Hello world");
}) }
为了让您的示例正常工作,main() 也可以是异步的并生成 2 个运行 a、b 并等待它们完成的线程:
#[tokio::main]
async fn main() {
let t1 = thread::spawn(|| {
a();
});
let t2 = thread::spawn(|| {
b();
});
t1.join().unwrap();
t2.join().unwrap();
}