Async
通过 async 标记的语法块会被转换成实现了Future特征的状态机。
与同步调用阻塞当前线程不同,在Async中, ,可以(我说的是可以,不是必须,怎么可以法看后面)当Future执行并遇到阻塞时,它会让出当前线程A的控制权,这样其它的Future就可以在该线程A中运行,这种方式完全不会导致当前线程的阻塞
一、创建和运行异步函数
先在package下的Cargo.toml下添加futures依赖
[dependencies]
futures = "0.3"
使用 async fn 语法来创建一个异步函数:
// `block_on`会阻塞当前线程直到指定的`Future`执行完成,这种阻塞当前线程以等待任务完成的方式较为简单、粗暴,
use futures::executor::block_on;
async fn hello_world() {
println!("hello, world!");
}
fn main() {
let future = hello_world(); // 返回一个Future, 因此不会打印任何输出
block_on(future); // 执行`Future`并等待其运行完成,此时"hello, world!"会被打印输出
}
block_on
运行一个future,并会阻塞当前线程(上面代码就是主线程)直到指定的Future
:(fn hello_world()
)执行完成,这种阻塞当前线程以等待任务完成的
二、非异步阻塞.await
async 修饰的函数 才能调用.await函数,async修饰函数表示这是一个新的future任务,可以在A函数异步非阻塞的方式运行一个B函数,
.await意思是需要等待异步调用的完成,才能往下运行,但是如果调用await的函数发生了阻塞,可以去调用别的future
都运行在同一个线程中。后面有例子进一步讲解,我们先看一个简单的熟悉一下语法
use futures::executor::block_on;
async fn hello_world() {
hello_cat().await;//需要等待hello_cat执行完,才执行println!("hello, world!");
//但是如果hello_cat()阻塞,可以去执行别的future,!!!而不是指往下执行println!("hello, world!")
println!("hello, world!");
}
async fn hello_cat() {//因为hello_cat是async修饰的,所以hello_cat能调用await
println!("hello, kitty!");
}
fn main() {
let future = hello_world();
block_on(future);
}
首先,整个代码运行在main线程这一个线程中,假设在hello_world()
函数中,调用了hello_cat().await
,表示异步非阻塞执行hello_cat函数,hello_cat也是一个future任务。执行完这个hello_cat函数,才可以继续执行hello_world()
后续代码。
异步非阻塞的意思是,如果在hello_world()
执行hello_cat
中,hello_cat
函数中发生阻塞行为,就不继续往下执行hello_world
这个future。转头去执行别的future任务
如果hello_cat
函数中没有发生阻塞行为,则按顺序执行完hello_cat
,再往下执行 hello_world
,运行期间,一直都是main线程在执行任务。
其实这里我有一个问题,多个future执行顺序是怎么样的,按创建顺序执行的吗?实践看看(默认是的)
三、进一步实践
实践讨论上面说的点
use std::time::Duration;
use tokio::time::sleep;
struct Song {
author: String,
name: String,
}
async fn learn_song() -> Song {
println!("{}","1.我先学唱歌");//最先打印1-》我先学唱歌
sleep(Duration::from_secs_f32(1 as f32)).await;//阻塞
println!("{}","3.学唱歌小睡了一下,醒来了");//阻塞结束,第三个打印3-》学唱歌小睡了一下,醒来了
Song {
author: "坤坤".to_string(),
name: String::from("《JntM》"),
}
}
async fn sing_song() {
println!(
"4.唱一首,{}的 {} ~ {}",
"vince", "fly", "music"
);//第四个打印!!!
}
async fn dance() {//这是一个future B
//阻塞等待,,再往下执行,打印“跳”
sleep(Duration::from_secs_f32(0.01)).await;//阻塞事件只有0.01s,比learn_song早唤醒
println!("2.跳");//所以第二个打印-》2.跳
}
async fn learn_and_sing() {//这是一个future A
//在 learn_and_sing内,需要按照顺序执行learn_song和sing_song两个内部future A_A,A_B
//先执行完learn_song,才能执行sing_song,learn_song内部有阻塞
learn_song().await;//learn_song有阻塞时间,阻塞时间为1s,转头执行另一个Feature B
//随着学唱歌结束,执行sing_song
sing_song().await;
}
#[tokio::main]
async fn main() {
let f1 = learn_and_sing();//这是一个future A,先执行这个
let f2 = dance();//这也是一个future B,后执行这个
futures::join!(f1, f2);
}
运行输出
1.我先学唱歌
2.跳
3.学唱歌小睡了一下,醒来了
4.唱一首,vince的 fly ~ music
详细解释都在代码中了
补充一下,在一个future A中,可以在future A中去执行别的future B,C ,但是这个是内部future,得保证在future A中,能运行到提交future B,C 的时候
1、block_up和.await的意义
在async函数中,创建future任务需要执行,不然等于没执行要么是backup执行,要么是await执行,其实就是async函数的执行方式
- backup是同步执行
- await才是异步非阻塞(不阻塞主线程)
执行的意思有点像,将函数加入到监听事件队列里面,你不执行t就不会监听,也就不会执行,
(1)没有使用await
我们可以看一段不加.await的代码
use std::time::Duration;
use tokio::time::sleep;
struct Song {
author: String,
name: String,
}
async fn learn_song() -> Song {
println!("{}","1.我先学唱歌");
println!("{}","3.学唱歌小睡了一下,醒来了");
Song {
author: "坤坤".to_string(),
name: String::from("《JntM》"),
}
}
async fn sing_song() {
sleep(Duration::from_secs_f32(1 as f32)).await;
println!(
"4.唱一首,{}的 {} ~ {}",
"vince", "fly", "music"
);//第四个打印!!!
}
async fn dance() {//这是一个future B
//阻塞等待,,再往下执行,打印“跳”
sleep(Duration::from_secs_f32(0.01)).await;//阻塞事件只有0.01s,比learn_song早唤醒
println!("2.跳");//所以第二个打印-》2.跳
}
async fn learn_and_sing() {//这是一个future A
//在 learn_and_sing内,只有一个sing_song的future被监听,所以只有sing_song的运行结果
learn_song();
//随着学唱歌结束,执行sing_song
sing_song().await;
}
#[tokio::main]
async fn main() {
let f1 = learn_and_sing();//这是一个future A,先执行这个
let f2 = dance();//这也是一个future B,后执行这个
futures::join!(f1, f2);
}
运行结果
2.跳
4.唱一首,vince的 fly ~ music
(2)使用同步阻塞调用block_on
我们可以用block_on来执行
use std::time::Duration;
use tokio::time::sleep;
use futures::executor::block_on;
struct Song {
author: String,
name: String,
}
async fn learn_song() -> Song {
println!("{}","1.我先学唱歌");
sleep(Duration::from_secs_f32(3 as f32)).await;//大睡3s看看情况
println!("{}","3.学唱歌小睡了一下,醒来了");
Song {
author: "坤坤".to_string(),
name: String::from("《JntM》"),
}
}
async fn sing_song() {
sleep(Duration::from_secs_f32(1 as f32)).await;
println!(
"4.唱一首,{}的 {} ~ {}",
"vince", "fly", "music"
);//第四个打印!!!
}
async fn dance() {//这是一个future B
//阻塞等待,,再往下执行,打印“跳”
sleep(Duration::from_secs_f32(0.01)).await;//阻塞事件只有0.01s,比learn_song早唤醒
println!("2.跳");//所以第二个打印-》2.跳
}
async fn learn_and_sing() {//这是一个future A
//在 learn_and_sing内,只有一个sing_song的future被监听,所以只有sing_song的运行结果
block_on(learn_song());
//随着学唱歌结束,执行sing_song
sing_song().await;
}
#[tokio::main]
async fn main() {
let f1 = learn_and_sing();//这是一个future A,先执行这个
let f2 = dance();//这也是一个future B,后执行这个
futures::join!(f1, f2);
}
运行结果
1.我先学唱歌
3.学唱歌小睡了一下,醒来了
2.跳
4.唱一首,vince的 fly ~ music