rust 中的语法await!正式改成.await, 关于Future这套东东,很有必要了解。象actix-web也已经1.0了,里面其实也是到处Future这套。async、await这套东东,是rust的硬知识。
一、async和await的几种形式
“async和其他Future是懒惰的:它们在运行之前什么都不做。运行Future的最常见方式是.await它。当在Future上调用.await时,它将尝试运行以完成它。如果Future被阻止,它将让出当前线程。当可以取得更多进展时,执行者将获取 Future并将继续运行,以便.await解决。”
1、async
(1)async fn
当然,也有很多情况,比如函数中有.await; 也可能没有.await的不同情况。这种也会导致,返回值也完全不一样。
比如,
1
2
3
4
5 1 async fn compute(){
2 println!("async->");
3 }
4
5
这个相当于:[只是相当于]
1
2
3
4
5 1 fn compute()->impl Future<Output = ()>{
2 println!("async->");
3 }
4
5
(2)async move
这种情况是,函数外面没有async 标识,此时,async move{}为返回值,放在函数里面,返回值是Future这套trait 的静态分发方式。
“async move块将获取它引用变量的所有权,允许它活得比目前的范围长,但放弃了与其他代码分享那些变量的能力”。
比如:
1
2
3
4
5
6
7
8
9
10
11 1 fn compute_01() -> impl Future<Output =Result<(),String>>{
2 async move{
3 for i in 1..10000{
4 let _ = i*2;
5 }
6 println!("=>01 it is over!");
7 Ok(())
8 }
9 }
10
11
(3)async闭包
1
2
3
4
5
6
7
8
9 1 fn compute_05(value:i32)->impl Future<Output=i32>{
2 let closure = async move |v:i32|{
3 compute_03().await;
4 v+1
5 };
6 closure(value)
7 }
8
9
2 、await
async并不必然就需要用await,但设计的初衷是想等.await调用。
在.await的调用上,需要注意两个方面,一方面是,什么情况下能用上.await;另一方面是, 用上.await函数本身有什么要求?
相当于,一个是从逻辑实质上的要求;另一个是外在形式上的要求;
(1)能用await的情况
await的用法很简单,一般主要有以下两个这中的一个条件,一种是显示的;一种是隐式的;
A、显示方式:调用的函数中与async相对应的安排的;比如,async; async move;
这种情况好理解,不详述。
B、隐式方式:没有明显的async相对应的安排,但函数的返回值实现了Future trait.
这种情况,是一种隐式的情况。比如,
1
2
3
4
5
6
7
8
9
10
11
12 1 struct data{
2 price :Vec<f64>
3 }
4 fn get_data(length: i64) ->data{
5 }
6 //但data 实现了Future trait, 即
7 impl Future for data{
8 // 省略......
9 }
10//即实现的函数,有Poll<Self::Output>
11
12
(2)await有用时,函数体外面是一定有async这个壳套着的;
也就是说,只有函数的签名中有async,才允许用.await的;
1
2
3
4
5 1async fn v(){
2 m().await // .await 是因为v()外面的签名,一定有一个async.
3}
4
5
另外,说明一下,当函数的返回值形式实现了impl Future<Output =Result<>>类型时,可以用.await?的形式。
3、block_on()
另外,提一下block_on(). 如果没有这个函数,所有的异步相当于“箭射出后,但收不回来”。
block_on() 相当于让这个异步安排强制完成。
二、实例
1、相关说明
(1)#![feature(async_await)]
有时,会更长一些,比如
#![feature(async_await, await_macro, futures_api)],具体来说,
async_await 增加了对 async fn 语法的支持。
await_macro 增加了对 await! 宏的支持。
futures_api 增加了对 nightly std::future 和 std::task 模块的支持,这些模块定义了核心Future特征和依赖类型。
(2)并在nightly的环境中
2、代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 1 #![feature(async_await)]
2 use std::thread;
3 use std::time::Duration;
4 use futures::{Future};
5 use futures::executor::block_on;
6
7 fn compute_01() -> impl Future<Output =Result<(),String>>{
8 async move{
9 for i in 1..10000{
10 let _ = i*2;
11 }
12 println!("=>01 it is over!");
13 Ok(())
14 }
15 }
16 async fn compute_02(){
17 println!("=>02 is entering....");
18 compute_01().await;
19 //compute_04().await;
20 println!("=>02 is over!");
21 }
22 async fn compute_03(){
23 println!("=>03 is entering....");
24 for i in 1..10000{
25 let _ = i*2;
26 }
27 println!("=>03 it is over!");
28 }
29 fn compute_04(){
30 println!("=> 04 is entering....")
31 }
32
33 fn compute_05(value:i32)->impl Future<Output=i32>{
34 let closure = async move |v:i32|{
35 compute_03().await;
36 v+1
37 };
38 closure(value)
39 }
40 fn main() {
41 block_on(compute_02());
42 //compute_03();
43 block_on(compute_03());//必须把这些异步跑完
44
45 let val = block_on(compute_05(6));
46 println!("val :{:?}",val);
47 println!("hello world!");
48 thread::sleep(Duration::from_millis(500000));
49 }
50
51
三、输出结果
1
2
3
4
5
6
7
8
9
10
11 1=>02 is entering....
2=>01 it is over!
3=>02 is over!
4=>03 is entering....
5=>03 it is over!
6=>03 is entering....
7=>03 it is over!
8val :7
9hello world!
10
11