专栏/Rust Async 3. 继续理解 Async

Rust Async 3. 继续理解 Async

2022年04月23日 04:20--浏览 · --喜欢 · --评论
粉丝:6.9万文章:25

         异步编程允许我们在同一个系统线程上所谓的同时运行多个任务,实现这个功能的诀窍就是当CPU等待外部事件或动作时(例如等待读写文件到磁盘、等待网络数据达到、等待定时器完成等),也就是一段代码或一个函数在等待的同时,异步运行时(例如tokio)会安排其他可继续执行的任务在CPU上执行。而当从磁盘或I/O子系统的系统中断到达的时候,异步运行时会知道识别这事,并安排原来的任务继续执行。

        一般来说,I/O受限(I/O Bound)的程序(程序执行的速度依赖于I/O子系统的速度)比起CPU受限(CPU Bound)的任务(程序执行的速度依赖于CPU的速度)可能更适合于异步任务的执行。但这只是一个一般性的指导方针,也有例外。


        async、.await关键字是Rust标准库里用于异步编程的内置核心原语集的代表。他们其实就是Rust里面特殊的语法糖,使开发人员更容易编写类似同步代码的异步代码。

        而Rust异步的核心其实是Future。Future是由异步计算或函数产生的单一最终值。Rust的异步函数都会返回Future,Future基本上就是代表着延迟的计算。

        我们之前的例子使用Future了吗?简单来说,是的。我们把之前的程序改一下写法:

        针对之前异步的例子代码,本例中我们没有修改main函数的代码,也就是说对read_file1()和read_file2()函数的调用代码没有变。而这两个函数签名改变了:

· 函数前async关键字去掉了;

· 函数返回值从String改为impl Future<Output=String>,也就是要求返回类型实现Future这个trait,最终的返回值类型是String;

· 原来函数体里的内容都套在了一个async块内(在函数或代码块前使用async关键字就会告诉编译器把代码转化为让其可以生成Future)。

 

        而这个例子的执行结果和之前异步例子是一样的:

 

        其实下面第一种写法就是第二种写法的语法糖而已:



        下面我们看一下Future的代码:

        Future就代表着异步的计算,其中的Output表示Future成功完成后返回的数据类型。

        poll方法对于异步程序非常重要。poll是被异步运行时调用,用来检查异步任务是否已经完成。poll方法返回一个枚举,该枚举有两个变体:

        其中Pending表示Future还没有完成;而Ready表示Future已经完成,它里面存放着返回的值。

 

        那么,谁来调用poll方法呢?Rust的Future需要有人不断跟进驱动Future来完成,就像一个事无巨细的项目经理。

        做这件事的就是异步执行器,它是异步运行时的一部分。异步执行器会管理一个Future的集合,并通过调用Future上的poll方法来驱动他们完成。所以函数或代码块在前面加上async关键字之后,就相当于告诉异步执行器(例如tokio的执行器)他会返回Future,这个Future需要被驱动直到完成。

 

        但是异步执行器(例如tokio的执行器)怎么知道异步已经准备好可以取得进展(可以产生值)了呢?他会持续不断的调用poll方法吗?

 

 

 



投诉或建议