Rust async understanding and preliminary preparation

Rust async understanding and preliminary preparation

Operating environment: win10 x64, rustc 1.57 0, author: Oolong Hari, date: December 31, 2021

1, Original program

Suppose we want to cook a meal now, and the stove has only one stove. The steps are generally as follows:
1. For pot washing, rice washing, etc., we set fn prepare()
2. Start cooking. We set it to fn cooking()
3. Wash dishes and so on. You can't fry until the rice is cooked. We set fn wash_vegetable()
The t rust program is as follows:

// #![allow(non_snake_case,unused)]
use std::thread::sleep;
use std::time::Duration;

fn prepare(){
    //prepare before cooking rice
    for i in 1..6 {
        println!("prepare:{}",i);
        sleep(Duration::from_millis(500));
    }
}

fn cooking(){
    println!("rice cooking...");
    for i in (1..=10).rev(){
        println!("cooking...{}",i);
        sleep(Duration::from_millis(500));
    }
    println!("rice cooked!!!");
}

fn wash_vegetable(){
    for i in 101..106{
        println!("vegetable washing:{}",i);
        sleep(Duration::from_millis(500));
    }
}

fn main(){
    prepare();
    cooking();
    wash_vegetable();
}

/*output:
prepare:1
prepare:2
prepare:3
prepare:4
prepare:5
rice cooking...
cooking...10
cooking...9
cooking...8
cooking...7
cooking...6
cooking...5
cooking...4
cooking...3
cooking...2
cooking...1
rice cooked!!!
vegetable washing:101
vegetable washing:102
vegetable washing:103
vegetable washing:104
vegetable washing:105
*/

Good sequential execution. However, it takes 10 time segments for the rice to be cooked. During this time, the above example is waiting for nothing. Can you wash the dishes first in the 10 time segments when the rice is cooked? The answer is yes, it needs to be parallel.

2, Thread thread

There are two kinds of parallel thread and asynchronous async. Let's use familiar threads to operate first.
The simplest idea is to put fn coooking() and FN wash in the main program ()_ The two functions vegetable () insert two threads respectively, and then let the thread run. Need to use std::tread::spawn This function.
First, let's put use std::thread::sleep; Change to use std::thread::{sleep,spawn};, Then you can happily change the main() main function. See the following for specific transformation:

use std::thread::{sleep,spawn};


fn main(){
    prepare();
    //spawn
    //Britain [spɔːn]
    //v.lay eggs;initiation;cause;cause;cause
    //n.(Fish, frogs, etc)egg
    let t1=spawn(cooking);
    let t2=spawn(wash_vegetable);
    t1.join().unwrap();
    t2.join().unwrap();
}
/*output:
prepare:1
prepare:2
prepare:3
prepare:4
prepare:5
rice cooking...
cooking...9
vegetable washing:101
vegetable washing:102
cooking...8
vegetable washing:103
cooking...7
vegetable washing:104
cooking...6
vegetable washing:105
cooking...5
cooking...4
cooking...3
cooking...2
cooking...1
cooking...0
rice cooked!!!
*/

I saw the output. Sure enough, I inserted the dish washing in the process of cooking.
The introduction thread can run according to the following routine.

1. let thread name = spawn (function name);
2. Thread name join();
In fact, the return value of spawn() is joinhandle < T >.

In a complete mess mumbo jumbo, many online tutorials are all too complicated. I make complaints about the non - class amateurs. It's still hard to chew and write by yourself. You don't need such a tall example.

The thread is out. I saw all kinds of asynchronous in balabala Say that threads are heavy and so on. Well, let's try to learn advanced technology.

3, Asynchronous async

Looking up the dictionary, async should be asynchronous or short for asynchronization. I remember that async await was cited by C# first, and now t rust also has it. Well, let's start learning.
Most recent versions of t rust use the standard library async_std, see Crate async_std and async-std . My basic understanding is that async and await are actually tags. You need to mark async before the synchronized function and mark async at the end of the waiting place await.
First, we have to rewrite the cargo of the project toml :

[dependencies]
async-std = { version = "1.2.0", features = ["attributes"] }

Then you need to reference use async in the program header_ std::task::{sleep,spawn};
Why use task::sleep? Because the time-consuming sleep() is the place that needs to be synchronized in the above program. The program of the above thread actually used its own thread::sleep early in the morning. Here, it is replaced with async_std::task. Of course, the fn prepare() function of the first rice washing does not need to be synchronized, but still uses std::thread::sleep to consume time.
The transformation is more troublesome than thread, and all functions need to participate in the transformation. Please remember: async and await are matched, which means that async must be marked in front of the function header where await exists, so the following main() main function needs to add compilation conditions: #[async#u STD:: Main]. The transformation is as follows:

 

// ref:https://docs.rs/async-std/latest/async_std/index.html
// cargo.toml
// [dependencies]
// async-std = { version = "1.2.0", features = ["attributes"] }
use async_std::task::{sleep,spawn};
use std::time::Duration;

fn prepare(){
    //prepare before cooking rice
    for i in 1..6 {
        println!("prepare:{}",i);
        std::thread::sleep(Duration::from_millis(500));
    }
}

async fn cooking(){
    println!("rice cooking...");
    for i in (0..10).rev(){
        println!("cooking...{}",i);
        //std::thread::sleep(Duration::from_millis(500));
        sleep(Duration::from_millis(500)).await;
    }
    println!("rice cooked!!!");
}

async fn wash_vegetable(){
    for i in 101..106{
        println!("vegetable washing:{}",i);
        //std::thread::sleep(Duration::from_millis(500));
        sleep(Duration::from_millis(500)).await;
    }
}

#[async_std::main]
async fn main(){
    prepare();
    let a1=spawn(cooking());
    let a2=spawn(wash_vegetable());
    a1.await;
    a2.await;
}

/*output:
prepare:1
prepare:2
prepare:3
prepare:4
prepare:5
rice cooking...
cooking...9
vegetable washing:101
cooking...8
vegetable washing:102
cooking...7
vegetable washing:103
cooking...6
vegetable washing:104
cooking...5
vegetable washing:105
cooking...4
cooking...3
cooking...2
cooking...1
cooking...0
rice cooked!!!
*/

be accomplished. Finally, I can simply use async.
To sum up, the purpose is to mark async in the function header of await where it takes too much time. While other functions want to use this time, they also need to mark async and await, so that they can run at the same time.

Keywords: Rust

Added by bobob on Tue, 04 Jan 2022 05:28:09 +0200