当前位置:网站首页>Rust中的Pin详解
Rust中的Pin详解
2022-06-27 06:36:00 【51CTO】
相关概念
Pin<P<T>>
这是一个struct,作用就是将P所指向的T在内存中固定住,不能移动。说白一些,就是不能通过safe代码拿到&mut T
。
Pin<P>
定义如下:
Unpin
这是一个trait,定义在std::marker
中,如果一个T: Unpin
,就说明T在pin后可以安全的移动,实际就是可以拿到&mut T
。
!Unpin
对Unpin取反,!Unpin的双重否定就是pin。如果一个类型中包含了PhantomPinned,那么这个类型就是!Unpin。
Pin<P>
的实现
我们这里只关注safe方法,重点是new方法:
可以看出,只有P所指向的T: Unpin
,才可以new出一个Pin<P<T>>
。这里的T就是应该被pin的实例,可是由于T: Unpin
实际上T的实例并不会被pin。也就是说,T没有实现Unpin trait时,T才会被真正的pin住。
由于Pin::new
方法要求T: Unpin
,通常创建一个不支持Unpin的T的pin实例的方法是用Box::pin
方法,定义如下:
例如,自定义了Node结构,如下的代码生成pin实例:
Node没有实现Unpin时,通过Pin的安全方法都不能得到&mut Node
,所以就不能移动Node实例。注意,这里是不能移动Node实例,node_pined是Pin实例,是可以移动的。
当然,通过Pin的unsafe方法,仍然可以得到mut Node
,也可以移动Node实例,但这些unsafe的操作就需要程序员自己去承担风险。Pin相关方法中对此有很详细的说明。
Pin可以被看作一个限制指针(Box<T>
或&mut T
)的结构,在T: Unpin
的情况下,Pin<Box<T>>
和Box<T>
是类似的,通过DerefMut
就可以直接得到&mut T
,在T没有实现Unpin的情况下,Pin<Box<T>>
只能通过Deref
得到&T
,就是说T被pin住了。
Pin这种自废武功的方法怪怪的,为什么要有Pin?虽然Box、Rc、Arc等指针类型也可以让实例在heap中固定,但是这些指针的safe方法会暴露出&mut T,这就会导致T的实例被移动,比如通过std::mem::swap
方法,也可以是Option::take
方法,还可能是Vec::set_len
、Vec::resize
方法等,这些可都是safe等方法。这些方法的共同点都是需要&mut Self
,所以说只要不暴露&mut Self
,就可以达到pin的目标。
为什么需要pin?
事情的起因就是Async/.Await异步编程的需要。
看看如下异步编程的代码:
rustc在编译是会自动生成类似如下的代码,其中的AsyncFuture会是一个自引用结构:
// The `Future` type generated by our `async { ... }` block
struct AsyncFuture {
...
fut_one: FutOne,
fut_two: FutTwo,
state: State,
}
// List of states our `async` block can be in
enum State {
AwaitingFutOne,
AwaitingFutTwo,
Done,
}
impl Future for AsyncFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
...
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
注意Future::poll
方法的第一个参数是Pin<&mut Self>
,如果在Future::poll
方法中有类似std::mem::swap
等方法调用,就有可能导致AsyncFuture被移动,那么AsyncFuture中的自引用field就会导致灾难。
可能你也注意到了,这里的Future::poll
代码是自动生成的,可以不调用std::mem::swap
等方法,就不会导致AsyncFuture被移动。的确是这样的,如果在这里将Future::poll
的第一个参数改为Box<Self>
或者&mut Self
,大概率是没有问题的。很多executor的实现,都是要求Future是支持Unpin,因为在poll代码中的确有修改Self的需求,但不会产生错误,也是这个原因。
但是,对于程序员实现Future的情况,问题就来了。**如果poll的参数是&mut Self,那么程序员就可能使用safe代码(比如std::mem::swap)产生错误,这是与rust安全编码的理念相冲突的。**这就是Pin引入的根本原因!
其实,在future 0.1版本中,poll的这个参数就是&mut Self
,如下:
总结一下
- Pin实际是对P指针的限制,在T没有实现Unpin的情况下,避免P指针暴露
&mut Self
。 - Pin的引入是Async/.Await异步编程的需要,核心就是
Future::poll
方法参数的需要。 - 除了
Future::poll
方法之外,不建议使用Pin,也没有必要使用Pin.
边栏推荐
- HTAP in depth exploration Guide
- Partial function of Scala
- How to download opencv? How to configure opencv after downloading?
- 路由器和交换机的区别
- Assembly language - Wang Shuang Chapter 8 two basic problems in data processing - Notes
- Active learning
- Meaning of 0.0.0.0:x
- 内存屏障今生之Store Buffer, Invalid Queue
- Xiaomi Interviewer: let's talk about the proficient Registration Center for three days and three nights
- An Empirical Evaluation of In-Memory Multi-Version Concurrency Control
猜你喜欢
Classical cryptosystem -- substitution and replacement
OPPO面试整理,真正的八股文,狂虐面试官
2022 CISP-PTE(二)SQL注入
The fourth question of the 299th weekly match 6103 Minimum fraction of edges removed from the tree
快速实现单片机和手机蓝牙通信
从5秒优化到1秒,系统飞起来了...
[QT] use structure data to generate read / write configuration file code
Caldera安装及简单使用
MPC control of aircraft wingtip acceleration and control surface
Configuring FTP, enterprise official website, database and other methods for ECS
随机推荐
TiDB 中的SQL 基本操作
Visual studio vs shortcut key usage
The number of query results of maxcompute SQL is limited to 1W
thrift
matlab GUI界面仿真直流电机和交流电机转速仿真
获取地址url中的query参数指定参数方法
小米面试官:听你说精通注册中心,我们来聊 3 天 3 夜
飞行器翼尖加速度和控制面的MPC控制
Scala advanced_ Member access modifier
[QT dot] realize the watchdog function to detect whether the external program is running
Redis cache penetration, cache breakdown, cache avalanche
el-select多个时,el-select筛选选中过的值,第二个el-select中过滤上一个选中的值
快速实现单片机和手机蓝牙通信
From 5 seconds to 1 second, the system flies
Ora-00909: invalid number of parameters, caused by concat
Interviewer: how to never migrate data and avoid hot issues by using sub database and sub table?
Yolov6's fast and accurate target detection framework is open source
IDEA中关于Postfix Completion代码模板的一些设置
[getting started] regular expression Basics
On gpu: historical development and structure