写时复制(Copy on Write)技术是一种程序中的优化策略,多应用于读多写少的场景。主要思想是创建对象的时候不立即进行复制,而是先引用(借用)原有对象进行大量的读操作,只有进行到少量的写操作的时候,才进行复制操作,将原有对象复制后再写入。这样的好处是在读多写少的场景下,减少了复制操作,提高了性能。

Rust中对应这种思想的是智能指针Cow<T>,定义如下:

pub enum Cow<'a, B>
where
B: 'a + ToOwned + 'a + ?Sized,
{
Borrowed(&'a B), //用于包裹引用
Owned(<B as ToOwned>::Owned), //用于包裹所有者
}

可以看到是一个枚举体,包括两个可选值,一个是“借用”,一个是“所有”。具体含义是:以不可变的方式访问借用内容,在需要可变借用或所有权的时候再克隆一份数据。

下面举个例子说明Cow<T>的应用:

use std::borrow::Cow;

fn abs_all(input: &mut Cow<[i32]>) {
for i in 0..input.len() {
let v = input[i];
if v < 0 {
input.to_mut()[i] = -v;
}
} println!("value: {:?}", input);
} fn main() {
// 只读,不写,没有发生复制操作
let a = [0, 1, 2];
let mut input = Cow::from(&a[..]);
abs_all(&mut input);
assert_eq!(input, Cow::Borrowed(a.as_ref())); // 写时复制, 在读到-1的时候发生复制
let b = [0, -1, -2];
let mut input = Cow::from(&b[..]);
abs_all(&mut input);
assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>); // 没有写时复制,因为已经拥有所有权
let mut input = Cow::from(vec![0, -1, -2]);
abs_all(&mut input);
assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>); let v = input.into_owned();
assert_eq!(v, [0, 1, 2]);
}

上面这个用例已经讲明了Cow<T>的使用,下面我们继续探索一下Cow<T>的实现细节。重点关注to_mutinto_owned的实现。

  • to_mut :就是返回数据的可变引用,如果没有数据的所有权,则复制拥有后再返回可变引用;
  • into_owned :获取一个拥有所有权的对象(区别与引用),如果当前是借用,则发生复制,创建新的所有权对象,如果已拥有所有权,则转移至新对象。
impl<B: ?Sized + ToOwned> Cow<'_, B> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
// 如果时借用,则进行复制;如果已拥有所有权,则无需进行复制
match *self {
Borrowed(borrowed) => {
*self = Owned(borrowed.to_owned());
match *self {
Borrowed(..) => unreachable!(),
Owned(ref mut owned) => owned,
}
}
Owned(ref mut owned) => owned, //这里解释了上个例子中,已拥有所有权的情况,无需再复制
}
} #[stable(feature = "rust1", since = "1.0.0")]
pub fn into_owned(self) -> <B as ToOwned>::Owned {
// 如果当前是借用,则发生复制,创建新的所有权对象,如果已拥有所有权,则转移至新对象。
match self {
Borrowed(borrowed) => borrowed.to_owned(),
Owned(owned) => owned,
}
}
}

最后,欢迎关注微信公众号,及时更新最新文章:

Rust写时复制Cow<T>的更多相关文章

  1. rust漫游 - 写时拷贝 Cow<'_, B>

    rust漫游 - 写时拷贝 Cow<'_, B> Cow 是一个写时复制功能的智能指针,在数据需要修改或者所有权发生变化时使用,多用于读多写少的场景. pub enum Cow<'a ...

  2. JAVA中写时复制(Copy-On-Write)Map实现

    1,什么是写时复制(Copy-On-Write)容器? 写时复制是指:在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改.修改 ...

  3. fork()和写时复制

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  4. Linux的fork()写时复制原则(转)

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  5. Linux进程管理——fork()和写时复制

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  6. 写时复制和fork,vfork,clone

    写时复制 原理: 用了“引用计数”,会有一个变量用于保存引用的数量.当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,当有类析构时, ...

  7. 用户空间缺页异常pte_handle_fault()分析--(下)--写时复制【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7955713 版权声明:本文为博主原创文章,未经博主允许不得转载. 在pte_handle_fa ...

  8. Redis持久化之父子进程与写时复制

    之所以将Linux底层的写时复制技术放在Redis篇幅下,是因为Redis进行RDB持久化时,BGSAVE(后面称之为"后台保存")会开辟一个子进程,将数据从内存写进磁盘,这儿我产 ...

  9. phpCOW机制(写时复制)

    写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改. COW最早应用在*nix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C ...

随机推荐

  1. denied: requested access to the resource is denied

    1.vim  /etc/docker/daemon.json    增加一个daemon.json文件 { "insecure-registries":["192.168 ...

  2. Ruby语言的一些杂项

    Ruby是纯正血统的面向对象语言,所有的一切,一切的一切都是对象 Ruby里块(语句块)的特性非常重要,这个优美的特性贯穿整个Ruby Ruby里模块和类的概念一样重要,模块也是Ruby里的一个非常优 ...

  3. ElasticStack学习(三):ElasticSearch基本概念

    1.文档 1)ElasticSearch是面向文档的,文档是所有可搜索数据的最小单位.例如: a)日志文件中的日志项: b)一张唱片的详细信息: c)一篇文章中的具体内容: 2)在ElasticSea ...

  4. 浅谈c++中的KMP

    百度上一些关于KMP算法的一些基本介绍 所谓KMP,其实就是一种经过改进的模式串匹配算法(即在原串A中查找是否存在模式串B) 通常情况下,我们是这样匹配的 串A    X Y Z X X Y Z X  ...

  5. scrapy基础知识之 RedisCrawlSpider:

    这个RedisCrawlSpider类爬虫继承了RedisCrawlSpider,能够支持分布式的抓取.因为采用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写pars ...

  6. [原创]Greenplum数据库集群实践

    GreenPlum实践 ============================================== 目录: 一.安装环境准备 二.GP数据库安装 三.集群添加standby节点 四. ...

  7. MFC在一个工程中启动其他工程的exe文件

    说明:有的时候把两个工程合并,但是偷懒不想在工程中添加代码,所以想到了这个办法,仅限偷懒哈哈哈哈 方法:新建一个主程序,在主程序的界面中添加按钮,在按钮的程序代码中添加以下语句: void CMain ...

  8. java.util.LinkedHashMap cannot be cast to

    Jackson转换泛型List出现错误java.util.LinkedHashMap cannot be cast to com.xxx ObjectMapper mapper = new Objec ...

  9. SVG波浪动画

    今天来试试用svg+css3制作波浪动画 下图是我制作出的效果 还不错吧 在制作波浪前,首先我们要画波浪啊,至于画波浪,如果你想直接通过计算贝塞尔曲线绘制出波浪... 好吧,那我也不拦着你 我就直接用 ...

  10. 简易数据分析 07 | Web Scraper 抓取多条内容

    这是简易数据分析系列的第 7 篇文章. 在第 4 篇文章里,我讲解了如何抓取单个网页里的单类信息: 在第 5 篇文章里,我讲解了如何抓取多个网页里的单类信息: 今天我们要讲的是,如何抓取多个网页里的多 ...