意外 tokio::task::spawn_blocking 行为
Unexpected tokio::task::spawn_blocking behavior
我正在试验 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();
}
}
我的期望是第一个功能块 运行 完整 - 只有这样第二个功能块才会 运行。这就是我对“spawn_blocking”的理解 - 它阻止进一步执行,直到完成其中的任何内容。
我实际得到的是第二个功能块首先开始(完整的,全部 10 个)——然后第一个功能块开始。所以这与我的预期完全相反。
为了进一步混淆事情,当我修改上面的代码使两个块都具有 spawn_blocking
时 - 所有 20 个函数一起开始,就好像两个块都是一个大异步循环的一部分。再次不是我的预期 - 我认为第一个块会 运行,在它完成之前阻塞,然后第二个会 运行.
谁能帮我解读一下这是怎么回事?
重现上述 2 个场景的完整代码可在 this repo 中找到。
- 场景 5 = 我描述的第一个案例
- 场景 6 = 我描述的第二种情况
注意:这里有两个级别的异步:BETWEEN 块和 WITHIN 块。希望有助于避免任何混淆。
听起来您希望 spawn_blocking
阻止 运行ning 的其他内容,但其目的恰恰相反。 spawn_blocking
的目的是 避免 阻塞 运行ning 的其他东西。
使用 spawn_blocking
的主要地方是用于原本会 block the thread 的操作,因为它们使用了非异步操作,例如 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();
}
请注意,在 spawn_blocking
中立即使用 #[tokio::main]
(或 block_on
)很少是您想要的。只需使用 tokio::spawn
.
生成一个普通任务
我正在试验 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();
}
}
我的期望是第一个功能块 运行 完整 - 只有这样第二个功能块才会 运行。这就是我对“spawn_blocking”的理解 - 它阻止进一步执行,直到完成其中的任何内容。
我实际得到的是第二个功能块首先开始(完整的,全部 10 个)——然后第一个功能块开始。所以这与我的预期完全相反。
为了进一步混淆事情,当我修改上面的代码使两个块都具有 spawn_blocking
时 - 所有 20 个函数一起开始,就好像两个块都是一个大异步循环的一部分。再次不是我的预期 - 我认为第一个块会 运行,在它完成之前阻塞,然后第二个会 运行.
谁能帮我解读一下这是怎么回事?
重现上述 2 个场景的完整代码可在 this repo 中找到。
- 场景 5 = 我描述的第一个案例
- 场景 6 = 我描述的第二种情况
注意:这里有两个级别的异步:BETWEEN 块和 WITHIN 块。希望有助于避免任何混淆。
听起来您希望 spawn_blocking
阻止 运行ning 的其他内容,但其目的恰恰相反。 spawn_blocking
的目的是 避免 阻塞 运行ning 的其他东西。
使用 spawn_blocking
的主要地方是用于原本会 block the thread 的操作,因为它们使用了非异步操作,例如 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();
}
请注意,在 spawn_blocking
中立即使用 #[tokio::main]
(或 block_on
)很少是您想要的。只需使用 tokio::spawn
.