Bootstrap

Rust : async、await 初探

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的不同情况。这种也会导致,返回值也完全不一样。
比如,

      async fn compute(){
          println!("async->");
      }

这个相当于:[只是相当于]

       fn compute()->impl Future<Output = ()>{
          println!("async->");
      }

(2)async 和async move

async {}后直接一个代码块。没有取环境变量的所有权。
“async move块将获取它引用变量的所有权,允许它活得比目前的范围长,但放弃了与其他代码分享那些变量的能力”。

比如:

  fn compute_01() -> impl Future<Output =Result<(),String>>{
    async move{
       for i in 1..10000{
          let _ = i*2;
       }
       println!("=>01 it is over!");
       Ok(())
    }
  }

(3)async闭包

  fn compute_05(value:i32)->impl Future<Output=i32>{
     let closure = async move |v:i32|{
        compute_03().await;
        v+1
     };
     closure(value)
  }

一个综合的例子:

sync fn hello(){
    println!("hello!");
    // async fn 
    async fn world(){
        println!("world!");
    }
    world().await;
    // async block
    let a = async{
        println!("{:?}","hello world!");
    };
    a.await;
    // async move block
    let code ="shang hai".to_string();
    let mut hp = HashMap::new();
    hp.insert("code","600036");
    let b = async move{
        println!("hello world, i love {:?}",hp);
    };
    //println!("code:{:?}",hp); //error if uncommented
    b.await;
}

2 、await
async并不必然就需要用await,但设计的初衷是想等.await调用。

在.await的调用上,需要注意两个方面,一方面是,什么情况下能用上.await;另一方面是, 用上.await函数本身有什么要求?
相当于,一个是从逻辑实质上的要求;另一个是外在形式上的要求;

(1)能用await的情况

await的用法很简单,一般主要有以下两个这中的一个条件,一种是显示的;一种是隐式的;

A、显示方式:调用的函数中与async相对应的安排的;比如,async; async move;

这种情况好理解,不详述。

B、隐式方式:没有明显的async相对应的安排,但函数的返回值实现了Future trait.

这种情况,是一种隐式的情况。比如,

  struct data{
       price :Vec<f64>
  }
  fn  get_data(length: i64) ->data{
  }
  //但data 实现了Future trait, 即
  impl Future for data{
     // 省略......
  }
//即实现的函数,有Poll<Self::Output>

(2)await有用时,函数体外面是一定有async这个壳套着的;

也就是说,只有函数的签名中有async,才允许用.await的;

async fn v(){
     m().await // .await 是因为v()外面的签名,一定有一个async.
}

另外,说明一下,当函数的返回值形式实现了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、代码

  #![feature(async_await)]
  use std::thread;
  use std::time::Duration;
  use futures::{Future};
  use futures::executor::block_on;

  fn compute_01() -> impl Future<Output =Result<(),String>>{
    async move{
       for i in 1..10000{
          let _ = i*2;
       }
       println!("=>01 it is over!");
       Ok(())
    }
  }
  async fn compute_02(){
      println!("=>02 is entering....");
      compute_01().await;
      //compute_04().await;
      println!("=>02 is over!");
  }
  async fn compute_03(){
    println!("=>03 is entering....");
    for i in 1..10000{
       let _ = i*2;
    }
    println!("=>03 it is over!");
  }
  fn compute_04(){
     println!("=> 04 is entering....")
  }

  fn compute_05(value:i32)->impl Future<Output=i32>{
     let closure = async move |v:i32|{
        compute_03().await;
        v+1
     };
     closure(value)
  }
  fn main() {
    block_on(compute_02());
    //compute_03();
    block_on(compute_03());//必须把这些异步跑完

    let val = block_on(compute_05(6));
    println!("val :{:?}",val);
    println!("hello world!");
    thread::sleep(Duration::from_millis(500000));
  }

三、输出结果

=>02 is entering....
=>01 it is over!
=>02 is over!
=>03 is entering....
=>03 it is over!
=>03 is entering....
=>03 it is over!
val :7
hello world!
;