我正在尝试 tokio 的结果tokio::spawn,tokio::task::spawn结果我不明白后者的行为方式。
当我运行以下代码时:
#[tokio::main]
pub async fn main() {
// I'm spawning one block of functions
let h = tokio::task::spawn_blocking(move || {
block_one();
});
// and another block of functions
let h2 = tokio::spawn(async move {
block_two().await;
});
// then I collect the handles
h.await.unwrap();
h2.await.unwrap();
}
#[tokio::main] //needed as this block is not treated as syncronous by main
pub async fn block_one() {
let mut handles = vec![];
for i in 1..10 {
let h = tokio::spawn(async move {
println!("Starting func #{}", i);
i_take_random_time().await;
println!("Ending func #{}", i);
});
handles.push(h);
}
for h in handles {
h.await.unwrap();
}
}
pub async fn block_two() {
let mut handles = vec![];
for i in 10001..10010 {
let h = tokio::spawn(async move {
println!("Starting func #{}", i);
i_take_random_time().await;
println!("Ending func #{}", i);
});
handles.push(h);
}
for h in handles {
h.await.unwrap();
}
}
Run Code Online (Sandbox Code Playgroud)
我的期望是第一个功能块将完整运行 - 然后第二个功能块才会运行。这就是我对“spawn_blocking”的理解——它会阻止进一步的执行,直到其中的内容完成为止。
我实际上得到的是,第二个函数块首先启动(总共 10 个函数)——然后第一个函数块才启动。所以这与我的预期完全相反。
更令人困惑的是,当我修改上面的代码以适用于spawn_blocking两个块时,所有 20 个函数一起启动,就好像两个块都是一个大异步循环的一部分一样。再次不是我所期望的 - 我认为第一个块会运行,在完成之前阻塞,然后第二个块会运行。
有人可以帮我破译发生了什么事吗?
此存储库中提供了重现上述 2 个场景的完整代码。
注意:这里有两个级别的异步性:BETWEEN块和WITHIN块。希望有助于避免任何混乱。
Ali*_*yhl 10
听起来您希望spawn_blocking阻止其他事物运行,但其目的恰恰相反。目的spawn_blocking是避免阻塞其他东西的运行。
主要spawn_blocking用于那些由于使用非异步操作(例如std::net. 它通过将它们卸载到单独的线程池来实现这一点。该名称源自这样一个事实:您正在生成一个阻塞操作,以便它可以在其他地方运行。
要等待第一个块完成,您可以这样做:
#[tokio::main]
pub async fn main() {
// I'm spawning one block of functions
let h = tokio::task::spawn_blocking(move || {
block_one();
});
// wait for the first block
h.await.unwrap();
// then spawn another block of functions
let h2 = tokio::spawn(async move {
block_two().await;
});
h2.await.unwrap();
}
Run Code Online (Sandbox Code Playgroud)
请注意,您很少需要在内部立即使用#[tokio::main](或block_on) 。spawn_blocking只需使用 生成一个普通任务即可tokio::spawn。
| 归档时间: |
|
| 查看次数: |
4243 次 |
| 最近记录: |