2

我有一个像这样的简单代码来模拟异步代码如何在阻塞操作上工作。

我希望所有这些“Hello”打印将在 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
4

2 回答 2

2

我怎样才能让它同时运行?

您可以:

您的期望可能来自 Javascript 或 C# async,其中“基础”等待是一个任务。任务是“活动的”,一旦您创建它们,它们就可以被安排并同时执行它们的事情。

但是 rust 的核心 awaitable 更像是一个coroutine,所以它是惰性的(/被动的):创建一个并没有真正做任何事情,future 必须被轮询才能进行,并且await反复轮询直到完成,然后再恢复。因此,当您await执行某些操作时,它会完全运行,此时没有机会交错。

因此,同时运行期货需要以下两件事之一:

  • 将它们升级为任务,这意味着它们可以自行安排,这spawn就是
  • 或者将期货组合成一个单一的“元期货”,当它被轮询时,它可以轮流轮询它们,这就是构造喜欢join_alltokio::join做的事情

请注意,组合期货不允许并行性,因为期货是“兄弟姐妹”,它们只能连续轮询(因此实际上做事情),只是这种轮询(以及进展)是交错的。

生成任务确实允许并行性(如果运行时是多线程的并且机器有多个内核——尽管后者现在几乎是通用的),但在生命周期和内存管理方面有其自身的局限性,而且成本更高一些.

这是各种选项的游乐场演示。它使用 tokio 是因为 Playground 显然没有 async_std,而且我不确定是否有可能启用“不稳定”功能,但除此之外以及使用tokio::join(async_std'sFuture::join只能加入 2 个期货时间所以你必须链接调用)它应该在 async_std 中工作大致相同。

于 2021-11-16T12:13:53.727 回答
0

futures我可以用crate 的方式做到这一点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;
}

于 2021-11-16T12:20:20.187 回答