rust异步编程Async背后原理
async 背后原理
- move 关键,能够让async 闭包和块使用,能够获取它引用变量所有权,使用父的变量,如下所示:
use futures::executor;
async fn move_block() {
let my_string = "foo".to_string();
let f = async move {
println!("{}", my_string);
};
// println!("{}", my_string); //此处不能再使用my_string
f.await
}
fn main() {
executor::block_on(move_block());
}
- async 背后关键字:
use futures::executor;
async fn async_function1() {
println!("async function1 !");
}
async fn async_function2() {
println!("async function2 !");
}
async fn async_main() {
let f1 = async_function1();
let f2 = async_function2();
//重点关注这里---------
let f = async move {
f1.await;
f2.await;
};
//---------------------
f.await;
// futures::join(f, async_function3());
}
对其展开分析
对于Future而言有 Pending,Ready状态
async 将 代码块转换成Future某个状态
struct AsyncFuture {
fut_one: FutFunction1,
fut_two: FutFunction2,
state: State
}
enum State {
AwaitFut1,
AwaitFut2,
Done,
}
-- Future的trait 的内部原理演示
impl Future for AsyncFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
loop {
match self.state {
State::AwaitFut1 => match self.fut_one.poll(...) {
Poll::Ready(()) => self.state = State::AwaitFut2,
Poll::Pending => return Poll::Pending,
}
State::AwaitFut2 => match self.fut_two.poll(...) {
Poll::Ready(()) => self.state = State::Done,
Poll::Pending => return Poll::Pending,
}
State::Done => return Poll::Ready(());
}
}
}
}
- 创建一个匿名的结构体
- 为结构体定义对应的状态
- 实现Future trait
Pin 内容
PIN使用场景从源头来说:async/await 的实现机制,从上面例子而言,对于闭包,编译器创建一个隐式的内部匿名struct 保存捕获到变量,对struct实现Call方法来实现函数的调用,由于需要记录当前状态(每一次await 时候都会导致一个状态),所以生成一个匿名enum , 每个enum变体保存从外部或者之前await捕获变量, enum充当函数的虚拟栈,主要因为如果保存在stack中,但是由于await 存在导致局部变量会从stack 中被删除(提出需要将匿名struct分配到堆上)-- 最大问题是rust对于自引用不能完美解决
async fn async_main() {
// 异步块
let f = async {
let mut x = [0: 128];
let async_put = async_put_data_to_buf(&mut x);
async_put.await;
};
}
--
自引用结构体
struct Foo {
array:[Bar; 10],
ptr: &'array Bar, // 内部ptr 指向的是其他Filed的元素,如果在Foo实例变量进行移动(memcpy),移动后ptr依然指向之前的地址,导致空指针异常,这就使用PIN 弱化版本智能指针解决问题
}
-- 这些变量需要分配在堆上
PIN 解决的问题:PIN类型包着指针类型, 保证指针类型背后值不被移动
PIN使用场景和抽象API了解点击
也就是说使用PIN指针 解决 自引用的变量被意外的移动后但是还是指向移动前地址,导致的空指针异常错误, PIN是一个弱化版本的BOx智能指针, 防止泄露&mut T 能够防止对象呗移动 Pin就像是一个铁笼子, 将自引用的猛兽关进去后,依然可以正常观察它,或者给它投点食物修改它,也可以把铁笼子移来移去,但不能把它放出来自由活动。
- PIN是零开销:
使用async构建异步逻辑时候并不需要每处都进行内存分配,将异步逻辑构建成一整个task放入到executor后最后在同一进行内存分配,这就是PIN零开销,将Future分配在堆上。 - PIN指针引入,使得rust代码在不使用unsafe 前提下,支持编译器生成的自引用结构,async 函数可以从虚拟栈中借用数据
-- 在没有使用PIN之前Future API: Vec<u8> 数据传递
pl Socket {
fn read(self, buf: Vec<u8>) ->
impl Future<Item = (Self, Vec<u8>, usize), Error = (Self, Vec<u8>, io::Error)>;
}
// 使用PIN之后
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> impl Future<Item = usize, Error = io::Error > 'a
-- 对应async函数 直接使用 ,不需要管自引用结构导致空指针异常
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error>;
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgkjjab
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13