004 rust asynchronous programming, detailed usage of async await

Time:2021-2-26

We briefly introduced the usage of async /. Await before, and we will introduce async /. Await in more detail in this section.

Usage of Async

There are two main uses of async: async function and asyn code block. These usages will return a future object, as follows:

async fn foo() -> u8 { 5 }

fn bar() -> impl Future<Output = u8> {
    // `Future<Output = u8>`.
    async {
        let x: u8 = foo().await;
        x + 5
    }
}

fn baz() -> impl Future<Output = u8> {
    // implements `Future<Output = u8>`
    let closure = async |x: u8| {
        let y: u8 = bar().await;
        y + x
    };
    closure(5)
}

The future object transformed by async is as inert as other future objects, that is, it does nothing before running. The most common way to run future is. Await.

The life cycle of Async

Consider an example:

async fn foo(x: &u8) -> u8 { *x }

According to our previous knowledge, this function is actually equivalent to the following:

fn foo<'a>(x: &'a u8) -> impl Future<Output = ()> + 'a {
    async { *x }
}

This asynchronous function returns a future object. If we pass the future object between threads, there will be a life cycle problem. As follows:

//There is a life cycle problem with this call
fn bad() -> impl Future<Output = ()> {
    let x = 5;
    foo(&x) // ERROR: `x` does not live long enough
}

The correct calling method is as follows:

fn good() -> impl Future<Output = ()> {
    async {
        let x = 5;
        foo(&x).await;
    }
}

Note: by moving the variable to async, the life cycle of X will be extended and the future life cycle returned by foo will be consistent.

async move

Async blocks and closures allow the move keyword, just like ordinary closures. An async move block will take ownership of the variables it references, allowing it to live longer than its current scope, but giving up the ability to share those variables with other code.

Examples are as follows

  • Profile:
    // Cargo.toml Add in
    [dependencies]
    futures = "0.3.4
  • Source code:
    //src/main.rs
    use futures::executor;
    async fn move_block() {
      let my_string = "foo".to_string();
      let f = async move {
          println!("{}", my_string);
      };
      // println!("{}", my_ String); // you can no longer use my here_ string
      f.await
    }
    fn main() {
      executor::block_on(move_block());
    }

Multithreading

When using multithreaded future’s executor, future may move between threads, so any variable used in async body must be able to transfer between threads, because any. Await variable may cause switching to a new thread.

This work adoptsCC agreementReprint must indicate the author and the link of this article

Linghu Yichong

Recommended Today

Third party calls wechat payment interface

Step one: preparation 1. Wechat payment interface can only be called if the developer qualification has been authenticated on wechat open platform, so the first thing is to authenticate. It’s very simple, but wechat will charge 300 yuan for audit 2. Set payment directory Login wechat payment merchant platform( pay.weixin.qq . com) — > Product […]