首页 > 其他分享 >rust学习十七.1、async和await

rust学习十七.1、async和await

时间:2025-01-16 16:47:12浏览次数:1  
标签:异步 title await future let async rust

本文对应相关书籍17.1章节。

先言:async和多线程没有什么密切关系,当然也不是毫无关系!

一、async在rust到底是什么

async中文的意思是异步,在编程中指的是:执行一段代码,主线程可以在等待完成之前,先做其它事情。

如果有写过前端代码,就明白这个东西。例如经典的jquery的ajax默认就是异步执行的。

 

原书花费了一段文字先解释:并行和并发

 * 1.并行(parallel)和并发(concurrency)都有一段时间内共同执行多个任务的意思
 * 2.并行指的是在同一时刻,有多个任务在执行。并发是指在某一时间段内,有多个任务在交替执行
 * 3.并发某种程度上理解为资源不够,分时处理;并行理解为资源充足,同时处理。
 * 4.当使用 Rust 中的 async 时,我们总是在处理并发
 * 5.取决于硬件、操作系统和所使用的异步运行时(async runtime)-- 稍后会介绍更多的异步运行时!
 *   并发也可能在底层使用了并行 --  这个需要特别注意

说了这么一大段就是为了说明一个事情:使用 Rust 中的 async 时,我们总是在处理并发

也就是说,一般情况下,在rust中使用异步,基本就是意味着是cpu分时处理,但具体怎么实现和代码以及系统系统有关!!!

 

二、async、await和future

await-等待

future-未来,rust中用于表示一个数据类型:现在不会有,但是过了一段时间会有

这些都是很熟悉的字眼,在java,js中是常常出现的。

 * 1.future 是一个现在可能还没有准备好但将在未来某个时刻准备好的值
 * 2.Rust 提供了 Future trait 作为基础组件,这样不同的异步操作就可以在不同的数据结构上实现
 * 3.每一个实现了 Future 的类型会维护自己的进度状态信息和 “ready” 的定义
 * 4.async 关键字可以用于代码块和函数
 * 5.在一个 async 块或 async 函数中,可以使用 await 关键字来等待一个 future 准备就绪,这一过程称为 等待一个 future
 * 6.检查一个 future 并查看其值是否已经准备就绪的过程被称为 轮询(polling)
 * 7.在大多数情况下,编写异步 Rust 代码时,我们使用 async 和 await 关键字。
 *    Rust 将其编译为等同于使用 Future trait 的代码,这非常类似于将 for 循环编译为等同于使用 Iterator trait 的代

 

三、示例

use trpl::{Either, Html};
use std::thread;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    println!("{:?}", args);

    //注意async关键字,并不会导致开启一个新的线程,仅仅意味着可以在内部使用await关键字等待异步操作完成。
    trpl::run(async {
        //lazy future 这里不会执行
        let title_fut_1 = page_title(&args[1]);
        //lazy future 这里不会执行
        let title_fut_2 = page_title(&args[2]);

        //race中的代码使用future::select执行并发,并返回最先完成的future。
        //因为这里真正开始执行,所以才会在多次运行的时候,返回可能不同的结果
        //race方法返回的是一个Either类型,Either是一个枚举类型,有两个值,Left和Right。
        let (url, maybe_title) = match trpl::race(title_fut_1, title_fut_2).await {
            Either::Left(left) => left,
            Either::Right(right) => right,
        };

        println!("{url} returned first");
        match maybe_title {
            Some(title) => println!("Its page title is: '{title}'"),
            None => println!("Its title could not be parsed."),
        }
    })
}
/**
 * 带了async的函数会返回一个future,这个future的类型是impl Future<Output = ()>,
 * output是一个泛型参数,这里是(),表示这个future的返回值是一个元组,
 */
async fn page_title(url: &str) -> (&str, Option<String>) {
    //这个语句会证实函数page_title是运行在主线程中...,并不是多线程的.
    println!("{}",url);
    println!("线程{:?}正在执行", thread::current().id());
    let text = trpl::get(url).await.text().await;
    let title = Html::parse(&text)
        .select_first("title")
        .map(|title| title.inner_html());
    (url, title)
}

 

注意:第一次执行,你会怀疑是不是卡死了,这个不是问题,是rusts-script需要耗费时间处理trpl(后者又依赖很多乱起八糟的),所以耗时颇长.

rust-script -d trpl 17.2_future.rs  https://www.cnblogs.com/lzfhope/p/18459068  https://www.cnblogs.com/lzfhope/p/18664452

这个命令执行了几次:

可以看到,结果会有所不同,这意味着 两个page_title在执行的时候不是固定,不是串行的!

 

这个trpl是rust提供的示例代码,下面是感兴趣的部分:

pub fn run<F: Future>(future: F) -> F::Output {
    let rt = Runtime::new().unwrap();
    rt.block_on(future)
}

pub async fn race<A, B, F1, F2>(f1: F1, f2: F2) -> Either<A, B>
where
    F1: Future<Output = A>,
    F2: Future<Output = B>,
{
    let f1 = pin!(f1);
    let f2 = pin!(f2);
    match future::select(f1, f2).await {
        Either::Left((a, _f2)) => Either::Left(a),
        Either::Right((b, _f1)) => Either::Right(b),
    }
}

 

这个Runtime是tokio单元包的成员,表示运行时(需要注意的是,rust反复强调运行时可以自建)

future::select 这个函数用于并发执行多个future,并返回一个future值。

四、简单执行async+await是什么样的?

前面的例子,有启用并发。 这也是常规的做法。

但是我也感兴趣,如果不用并发又是什么样的?

先说结论:就是什么也没有发生

use std::thread;

struct Hero {
    name: String,
    age: u32,
}

fn main() {
    let hero = Hero {name: "孙悟空".to_string(),age: 100,};
    let ws = Hero {name: "武松".to_string(),age: 99,};
    let str1 = run(&hero);
    let str2 = run(&ws);
}

async fn fight(h: &Hero) -> String {
    let temp = h.name.clone() + "正在战斗中....";
    println!("{}", temp);
    temp.to_string()
}
//这个方法要返回实现Debug特质的类型
async fn run(h: &Hero) -> String {
    let r = fight(&h).await;
    println!("{}", r);
    r
}

 

五、小结

  顺便也看了一些其它的资料。

  1. 创建异步函数的方式:函数(代码块)前加async,在函数体内添加await。 例外情况:不能把main标记为async
  2. 异步函数可以采用rust现有的两个异步运行时来运行:tokio或者async-std。似乎没有更多选择,此外为什么又那么多运行时,难道这个不应该是rust核心库的功能吗
  3. 异步的底层实现可能不一定是并发,也可能是并行,要看情况而定
  4. async函数默认返回的是 Future<Output = ()>。奇怪的语法又出现了,rust不要求你把返回结果显示地定义为Future。看第一个实例的page_title函数
    • 希望rust少一些这种默认的东西
    • 少一些故意和其它语言不同的东西
    • 此外,我也好奇,如果特意把返回类型写成Future会怎么样?
  5.  看了这些内容,距离异步编程还差99%

标签:异步,title,await,future,let,async,rust
From: https://www.cnblogs.com/lzfhope/p/18671345

相关文章

  • Rust程序Vec中存储的一般都是Box动态指针吗?
    Rust程序Vec中存储的一般都是Box动态指针吗?UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU在Rust中,Vec<T>不是专门存储Box<T>或其他动态指针,而是存储类型T的值。具体来说,Vec<T>会按照值的类型T来管理数据,它通常使用堆分配内存来存储数据(对于较大的数据或当数据需要动态增长时......
  • Rust如何在代码中查看一个变量的数据类型?
    Rust如何在代码中查看一个变量的数据类型?UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU在Rust中,你可以使用std::any::TypeId来查看一个变量的类型,但是这种方式通常用于调试或元编程,而不是日常开发的主要方法。Rust是强类型语言,通常在编译时就能检查类型,开发者无需显式查看类型。但......
  • @await Html.PartialAsync
    @awaitHtml.PartialAsync是ASP.NETCoreMVC中的一个Razor视图语法,用于异步加载一个视图片段(PartialView)。作用视图复用:可以将一些通用的UI组件或内容封装成视图片段,然后在不同的页面或视图中通过 @awaitHtml.PartialAsync 来引入,避免代码重复,提高开发效率和代码的......
  • 【转】[C#] WebAPI 使用async和await
    转自:kimi.ai在.NETFramework4.5及以上版本中,WebAPI支持async和await关键字的使用。使用async和await对调用方(客户端)和服务器端都有不同的影响,以下是详细说明:对调用方(客户端)的影响响应时间:对于单个客户端请求来说,使用async并不会显著减少请求的响应时间。无论是同步还是......
  • Autopy 是一款基于 Python 和 Rust 的强大 GUI 自动化库
    Autopy是一款基于Python和Rust的强大GUI自动化库,它为开发者提供了简便且高效的API来模拟鼠标和键盘的操作、在屏幕上查找颜色和位图以及显示警报。这些功能使得Autopy成为了一个跨平台的自动化工具,适用于MacOSX、Windows以及支持XTest扩展的X11系统。跨......
  • 手机端rustdesk如何进行配置
    安装rustdesk客户端以后,可以按照下图填写配置信息手机版也是可以快速导入导出,可以方便从其他设备或者客户端直接导入配置信息,然后在本软件进行导入或者导出......
  • rustdesk如何开启远程教程
    手机端在软件底部选择【共享屏幕】,在共享屏幕里面选择启动服务。主控和被控手机同时都配置好了ID服务器的信息以后,在软件底部选择【连接】然后输入远程ID,选择连接就行了。提示输入密码,可以查看一下被控客户端的密码,或者可以给被控客户端设置固定密码。......
  • TrustRAG:增强RAG系统鲁棒性与可信度的创新框架
    在人工智能飞速发展的今天,大语言模型(LLMs)凭借其强大的语言处理能力在诸多领域大放异彩。检索增强生成(RAG)系统(面向企业RAG(RetrievalAugmentedGeneration)系统的多维检索框架)的出现,通过整合外部知识源进一步提升了LLMs的性能,使其能针对用户查询提供更准确、更具上下文相关性的......
  • 请说说`<script>`、`<script async>`和`<script defer>`的区别
    在前端开发中,<script>标签用于嵌入或引用JavaScript代码。<script>标签有几个属性可以影响脚本的加载和执行方式,其中async和defer是两个常用的属性。以下是它们之间的主要区别:普通的<script>:当浏览器遇到<script>标签时,它会立即下载并执行该脚本。在执行脚本期......
  • Rust 和 Tesseract OCR 实现英文数字验证码识别
    Rust是一门注重内存安全并具有高性能的系统编程语言。它通过并发机制和零成本抽象提供了强大的功能。我们可以利用Rust的库来调用TesseractOCR实现验证码识别。一、安装与配置安装TesseractOCR同样,首先要在系统中安装TesseractOCR。Ubuntu(Linux):bashsudoaptupda......