【问题标题】:what is the meaning of "await" used in Rust?Rust中使用的“等待”是什么意思?
【发布时间】:2020-02-15 13:24:43
【问题描述】:

这个问题可能比 Rust 更多地与异步编程有关。但是在谷歌上搜索了很多之后,我认为仍然缺少一些点。而且由于我正在学习 Rust,所以我会用 Rust 的方式来描述它。

先说说我对async-programming的理解---毕竟这是基础,也许我错了:

为了使程序高效运行,并发处理任务是必不可少的。然后使用线程,只要需要来自线程的数据,就可以加入线程。但是线程不足以处理许多任务,就像服务器一样。然后使用了线程池,但是在没有关于应该等待哪个线程的信息的情况下,如何在需要时获取数据?然后回调函数(简称cb)出现。有了cb,只需要考虑cb中需要做的事情。此外,为了减少 cpu 的开销,出现了绿色线程。

但是如果异步等待的事情需要一个接一个地做,导致“回调地狱”怎么办?好的,“future/promise”样式出现了,它让代码看起来像同步代码,或者可能像一个链(就像在 javascript 中一样)。但是代码仍然看起来不太好。最后,出现了“async/await”风格,作为“future/promise”风格的另一种语法糖。而且通常,带有绿色线程样式的“async/await”称为“协程”,无论是仅使用一个本地线程还是使用多个本地线程处理异步任务。

==============================================

据我所知,as关键字“await”只能在“async”函数的范围内使用,并且只有“async”函数才能被“awaited”。但为什么?以及它是用来做什么的,因为已经有“异步”了? 无论如何,我测试了下面的代码:

use async_std::{task};


// async fn easy_task() {
//     for i in 0..100 {
//         dbg!(i);
//     }
//     println!("finished easy task");
// }

async fn heavy_task(cnt1: i32, cnt2: i32) {
    for i in 0..cnt1 {
        println!("heavy_task1 cnt:{}", i);
    }

    println!("heavy task: waiting sub task");
    // normal_sub_task(cnt2);
    sub_task(cnt2).await;
    println!("heavy task: sub task finished");

    for i in 0..cnt1 {
        println!("heavy_task2 cnt:{}", i);
    }
    println!("finished heavy task");
}

fn normal_sub_task(cnt: i32) {
    println!("normal sub_task: start sub task");
    for i in 0..cnt {
        println!("normal sub task cnt:{}", i);
    }
    println!("normal sub_task: finished sub task");
}

async fn sub_task(cnt: i32) {
    println!("sub_task: start sub task");
    for i in 0..cnt {
        println!("sub task cnt:{}", i);
    }
    println!("sub_task: finished sub task");
}

fn outer_task(cnt: i32) {
    for i in 0..cnt {
        println!("outer task cnt:{}", i);
    }
    println!("finished outer task");
}

fn main() {
    // let _easy_f = easy_task();
    let heavy_f = heavy_task(3000, 500);
    let handle = task::spawn(heavy_f);
    print!("=================after spawn==============");
    outer_task(5000);

    // task::join_handle(handle);
    task::block_on(handle);
}

我从测试中得到的结论是:

1.无论是async Heavy_task()中间等待async sub_task还是做normal_sub_task(sync version),下面的代码(heavy loop task2)都不会插队。

2.无论是等待async sub_task还是只是在async heavy_task()中间做normal_sub_task(同步版本),outer_task有时会插队,破坏heavy_task1或async_sub_task/normal_sub_task。

所以“await”是什么意思,这里好像只用了关键字“asyc”。

参考:

asyc_std

sing_dance_example from rust asyncbook

module Task in official rust module

recommended article of rust this week about async-programming

another article about rust thread and async-programming using future crates

stackoverflow question:What is the purpose of async/await in Rust? 我得到的结论 2 似乎违反了 Shepmaster 所说的“......我们认为异步函数应该与第一个等待同步运行。”

【问题讨论】:

  • 如果 async/await 的工作方式与 C# 中相同,那么它不是为了并行化,而是让当前线程在等待某个 IO 任务完成时可以做其他工作。而你没有任何
  • 请注意,您的代码中没有任何内容实际上是异步的。你甚至有 blocking 调用 (println!) 和计算。您不能只将 async 关键字添加到函数中以使其异步,这需要更多的工作(否则它可以完全自动化,并且我们不需要新的关键字)。
  • 你需要复习并发的基础知识。您的基本理解有些不准确。

标签: multithreading asynchronous rust async-await


【解决方案1】:

await 关键字暂停异步函数的执行,直到等待的未来 (future.await) 产生一个值。

使用 await 概念的所有其他语言的含义相同。

当等待一个未来时,async 函数的“执行状态”被持久化到一个内部 执行上下文和其他异步函数在准备好运行时有机会继续运行。

当等待的 future 完成时,异步函数会在暂停的确切点恢复。

如果你认为我只需要 async 并写如下内容:

// OK: let result = future.await
let result = future

你得到的不是价值,而是代表未来准备好的价值的东西。

如果你标记 async 一个函数而不等待里面的任何东西 您要注入异步引擎的函数主体 顺序任务 执行时将作为正常功能运行完成,防止异步行为。

更多关于你的代码的 cmets

可能是由于对任务概念的误解造成的。

在 rust 中学习异步时,我发现 async book 非常有用。

本书将任务定义为:

任务是已提交给执行者的顶级期货

heavy_task 在您的示例中确实是唯一的任务,因为它是提交给异步的唯一未来 task::block_on 的运行时。

例如函数outer_task与异步世界无关: 这不是一个任务,它在调用时立即执行。

heavy_task 行为异步并等待 sub_task(cnt2)future ... 但 sub_taskfuture 一旦执行 立即完成。

因此,就目前而言,您的代码实际上是按顺序运行的。

但请记住,现实中的事情更加微妙,因为在存在其他异步任务时 await inside heavy_task 作为一个暂停点,给其他人机会 即将完成的任务。

【讨论】:

  • 感谢您的回答。关于“异步函数中没有等待”的最后一个声明,我之前也听说过。但正如我测试的那样,在heavy_task 中使用normal_sub_task,outer_task 和heavy_task 确实是异步工作的。我不知道为什么。
  • 我已经用一些细节更新了答案。我希望它可以帮助。
  • 感谢您的更新。但我仍然对你的话感到困惑“......但是 sub_task 未来一旦执行就会立即完成。所以,就目前而言,你的代码实际上是按顺序运行的。”从我得到的 2ed 结论中,我在问题中说,sub_task 总是被 outer_task 打断,无论是异步(sub_task.await)还是​​同步版本(直接调用 normal_sub_task)。所以如果你说的“顺序”是关于heavy_task中的顺序,我完全同意——因为它总是顺序的!而outer_task总是中断异步heavy_task ..(未完成)
  • ..在任何部分。所以即使我猜你提到的“顺序”是关于outer_task和异步heavy_task之间的顺序,正如我测试过的那样,它是“总是”“不连续” - 详细地说,outer_task会中断“heavy_task1”, “heavy_task2”甚至是“sub_task().await”和“normal_sub_task(cnt2)”。因此,我得到了两个结论,这就是为什么我认为 await 没有意义然后提出问题。 (完成)
  • 我认为您仍然感到困惑,因为在您的心智模型中task::spawn(heavy_f) 开始执行heavy_task。这不是真的。 eavy_tasktask::block_on(handle) 之后开始运行。我再次强调outer_task 不是异步任务。
猜你喜欢
  • 1970-01-01
  • 2022-10-02
  • 2017-10-31
  • 2022-07-22
  • 2020-06-20
  • 1970-01-01
  • 2016-09-21
  • 2023-01-19
  • 1970-01-01
相关资源
最近更新 更多