首页 > 编程语言 >005 Rust异步编程,Pin介绍

005 Rust异步编程,Pin介绍

时间:2022-11-07 11:36:09浏览次数:40  
标签:mut fut Pin let 005 async buf Rust


为了对Future调用poll,需要使用到Pin的特殊类型。本节就介绍一下Pin类型。

异步背后的一些原理

例子1

  • 源码
//文件src/main.rs
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;
}

fn main() {
executor::block_on(async_main());
}
  • 配置,在Cargo.toml中添加
[dependencies]
futures = "0.3.4

我们主要考虑async_main()函数中的async块(async函数也是一样,通过async都是转化为Future),实际背后会做如下工作:
(1)为async块生成一个类似于如下的结构体:

struct AsyncFuture {
fut_one: FutFunction1,
fut_two: FutFunction2,
state: State,
}

//state的定义可能如下
enum State {
AwaitingFutFunction1,
AwaitingFutFunction2,
Done,
}

(2)为其生成对应的poll函数:

impl Future for AsyncFuture {
type Output = ();

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
loop {
match self.state {
State::AwaitingFutFunction1 => match self.fut_one.poll(..) {
Poll::Ready(()) => self.state = State::AwaitingFutFunction2,
Poll::Pending => return Poll::Pending,
}
State::AwaitingFutFunction2 => match self.fut_two.poll(..) {
Poll::Ready(()) => self.state = State::Done,
Poll::Pending => return Poll::Pending,
}
State::Done => return Poll::Ready(()),
}
}
}
}

好,到这里,我们只是模拟编译器给async代码块进行了展开,那么和我们要讲的Pin有什么关系呢?

例子2

我们再考虑如下例子:

async fn async_put_data_to_buf(mut buf: &[u8]) {
//to do
...
}

async fn async_main () {
//重点关注这里---------
let f = async {
let mut x = [0; 128];
let read_into_buf_fut = async_put_data_to_buf(&mut x);
read_into_buf_fut.await;
};
//---------------------

f.await;
}

对于上面async_main中的async块,编译器为其生成的结构如下:

struct ReadIntoBuf<'a> {
buf: &'a mut [u8], // points to `x` below
}

struct AsyncFuture {
x: [u8; 128],
read_into_buf_fut: ReadIntoBuf<'what_lifetime?>,
}

在AsyncFuture中,read_into_buf_fut.buf指向x,相当于是一个自引用(一个字段引用另一个字段)。但是如果AsyncFuture发生移动,x肯定也会发生移动,如果read_into_buf_fut.buf还是指向原来的值的话,则会变成无效。
而Pin就是为了解决此问题的。

Pin介绍

Pin类型包着指针类型,保证指针背后的值将不被移动。例如 Pin<&mut T>,Pin<&T>, Pin<Box> 都保证 T 不会移动。

拿上面的例子来说,如果使用Pin<>就是将x对应的那块内存固定,这样即使AsyncFuture发生移动,但是x不会移动,那么read_into_buf_fut.buf不会变成悬垂引用。

大多数类型都没有移动的问题,这些类型实现了 Unpin trait。Unpin 类型指针可以自由从 Pin 中放入或取出。例如,u8 就是 Unpin的。

如果需要Future和Unpin一起使用,则需要使用Pin<Box>或者pin_utils::pin_mut!,例子如下:

use pin_utils::pin_mut; // `pin_utils` is a handy crate available on crates.io

// A function which takes a `Future` that implements `Unpin`.
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { /* ... */ }

let fut = async { /* ... */ };
execute_unpin_future(fut); // Error: `fut` does not implement `Unpin` trait

// Pinning with `Box`:
let fut = async { /* ... */ };
let fut = Box::pin(fut);
execute_unpin_future(fut); // OK

// Pinning with `pin_mut!`:
let fut = async { /* ... */ };
pin_mut!(fut);
execute_unpin_future(fut); // OK


标签:mut,fut,Pin,let,005,async,buf,Rust
From: https://blog.51cto.com/u_15862521/5828347

相关文章

  • Rust 编程中使用 leveldb 的简单例子
    前言最近准备用Rust写一个完善的blockchain的教学demo,在持久化时考虑到使用leveldb。通过查阅文档,发现Rust中已经提供了使用leveldb的接口。将官方的例子修改了下,能够运行通......
  • 用Rust刷leetcode第八题
    ProblemImplement ​​atoi​​​ which convertsastringtoaninteger.Thefunctionfirstdiscardsasmanywhitespacecharactersasnecessaryuntilthefirst......
  • 023 通过链表学Rust之非安全方式实现链表1
    介绍视频地址:https://www.bilibili.com/video/av78062009/相关源码:https://github.com/anonymousGiga/Rust-link-list链表定义我们重新定义链表如下:pubstructList<T>{......
  • 022 通过链表学Rust之为什么要非安全的单链表
    介绍视频地址:https://www.bilibili.com/video/av78062009/相关源码:https://github.com/anonymousGiga/Rust-link-list详细内容前面我们都是使用安全的Rust编程来实现链表,但......
  • 025 通过链表学Rust之使用栈实现双端队列
    介绍视频地址:https://www.bilibili.com/video/av78062009/相关源码:https://github.com/anonymousGiga/Rust-link-list详细内容本节我们使用栈来实现双端队列。实现栈栈的实......
  • 024 通过链表学Rust之非安全方式实现链表2
    介绍视频地址:https://www.bilibili.com/video/av78062009/相关源码:https://github.com/anonymousGiga/Rust-link-list详细内容本节实现剩余的迭代器、Drop等。IntoIter实现......
  • 用Rust实现一个多线程的web server
    在本文之前,我们用Rust实现一个单线程的webserver的例子,但是单线程的webserver不够高效,所以本篇文章就来实现一个多线程的例子。单线程webserver存在的问题请求只能串行处......
  • 用Rust创建一个简单的webserver
    目的本节的例子教大家用Rust语言创建一个简单的webserver程序。webserver中涉及到的两个主要协议是超文本传输协议(HypertextTransferProtocol,HTTP)和传输控制协议(Tran......
  • 42. Trapping Rain Water
    Given n non-negativeintegersrepresentinganelevationmapwherethewidthofeachbaris1,computehowmuchwateritisabletotrapafterraining.Theab......
  • Rust 2022
    fngreet(language:&str)->&str{returnmatchlanguage{"english"=>"Welcome","czech"=>"Vitejte","danish"=>"V......