如何使用async_std::task::sleep模拟阻塞操作?
How to use async_std::task::sleep to simulate blocking operation?
我有一个像这样的简单代码来模拟异步代码如何处理阻塞操作。
我希望所有这些“你好”打印将在 1000 毫秒后显示。
但是这段代码像普通的阻塞代码一样工作,每个 hello_wait 调用等待 1000 毫秒并在 1000 毫秒后打印另一个 Hello。
我怎样才能运行并发?
use std::{time::Duration};
use async_std::task;
async fn hello_wait(){
task::sleep(Duration::from_millis(1000)).await;
println!("Hello");
}
#[async_std::main]
async fn main() {
hello_wait().await;
hello_wait().await;
hello_wait().await;
hello_wait().await;
hello_wait().await;
}
这是正在发生的事情:
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
这就是我想要的:
// -- Wait 1000ms --
Hello
Hello
Hello
Hello
Hello
How can I make it run concurrently?
您可以:
- spawn a task,这将使每个
hello_wait
独立安排
- 或"merge" the futures,这将并行驱动所有期货
您的期望可能来自 Javascript 或 C# async,其中可等待的“基础”是 任务。任务是“活动的”,一旦您创建它们,它们就可以被安排并同时做它们的事情。
但是 Rust 的核心 awaitable 更像是一个 coroutine,所以它是 inert (/ passive):创建一个并不能真正做到任何事情,futures 都必须被轮询才能取得进展,await
将 重复轮询直到完成 才能继续。因此,当您 await
某些东西时,它会完全运行,此时没有机会交错。
因此 运行 期货同时需要两件事之一:
- 将它们升级为任务,这意味着它们可以自行安排,这就是
spawn
所做的
- 或者将未来组合成一个单一的“元未来”,它可以在轮询时轮流轮询它们,这就是像
join_all
or tokio::join
这样的结构
请注意,组合 futures 不允许 并行性 ,因为 futures 是“兄弟姐妹”,它们只能连续轮询(因此实际上做事),只是这个轮询(以及进度)交织在一起。
生成任务确实允许并行(如果运行时是多线程的并且机器有多个内核——尽管后者现在非常普遍),但在生命周期和内存管理方面有其自身的局限性,并且就是贵了点。
Here is a playground demo of various options。它使用 tokio 因为显然 playground 没有 async_std,而且我不确定是否有可能启用“不稳定”功能,但除此之外还有 tokio::join
的使用(async_std 的 Future::join
一次只能加入 2 个期货,所以你必须链接调用)它应该在 async_std.
中大致相同
我可以用 futures
板条箱的 join_all
:
这样做
use std::time::Duration;
use async_std::task;
use futures::future;
async fn hello_wait(){
task::sleep(Duration::from_millis(1000)).await;
println!("Hello");
}
#[async_std::main]
async fn main() {
let mut asyncfuncs = vec![];
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
future::join_all(asyncfuncs.into_iter()).await;
}
我有一个像这样的简单代码来模拟异步代码如何处理阻塞操作。
我希望所有这些“你好”打印将在 1000 毫秒后显示。
但是这段代码像普通的阻塞代码一样工作,每个 hello_wait 调用等待 1000 毫秒并在 1000 毫秒后打印另一个 Hello。
我怎样才能运行并发?
use std::{time::Duration};
use async_std::task;
async fn hello_wait(){
task::sleep(Duration::from_millis(1000)).await;
println!("Hello");
}
#[async_std::main]
async fn main() {
hello_wait().await;
hello_wait().await;
hello_wait().await;
hello_wait().await;
hello_wait().await;
}
这是正在发生的事情:
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
// -- Wait 1000ms --
Hello
这就是我想要的:
// -- Wait 1000ms --
Hello
Hello
Hello
Hello
Hello
How can I make it run concurrently?
您可以:
- spawn a task,这将使每个
hello_wait
独立安排 - 或"merge" the futures,这将并行驱动所有期货
您的期望可能来自 Javascript 或 C# async,其中可等待的“基础”是 任务。任务是“活动的”,一旦您创建它们,它们就可以被安排并同时做它们的事情。
但是 Rust 的核心 awaitable 更像是一个 coroutine,所以它是 inert (/ passive):创建一个并不能真正做到任何事情,futures 都必须被轮询才能取得进展,await
将 重复轮询直到完成 才能继续。因此,当您 await
某些东西时,它会完全运行,此时没有机会交错。
因此 运行 期货同时需要两件事之一:
- 将它们升级为任务,这意味着它们可以自行安排,这就是
spawn
所做的 - 或者将未来组合成一个单一的“元未来”,它可以在轮询时轮流轮询它们,这就是像
join_all
ortokio::join
这样的结构
请注意,组合 futures 不允许 并行性 ,因为 futures 是“兄弟姐妹”,它们只能连续轮询(因此实际上做事),只是这个轮询(以及进度)交织在一起。
生成任务确实允许并行(如果运行时是多线程的并且机器有多个内核——尽管后者现在非常普遍),但在生命周期和内存管理方面有其自身的局限性,并且就是贵了点。
Here is a playground demo of various options。它使用 tokio 因为显然 playground 没有 async_std,而且我不确定是否有可能启用“不稳定”功能,但除此之外还有 tokio::join
的使用(async_std 的 Future::join
一次只能加入 2 个期货,所以你必须链接调用)它应该在 async_std.
我可以用 futures
板条箱的 join_all
:
use std::time::Duration;
use async_std::task;
use futures::future;
async fn hello_wait(){
task::sleep(Duration::from_millis(1000)).await;
println!("Hello");
}
#[async_std::main]
async fn main() {
let mut asyncfuncs = vec![];
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
asyncfuncs.push(hello_wait());
future::join_all(asyncfuncs.into_iter()).await;
}