写时复制(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. Java NIO 学习笔记(四)----文件通道和网络通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  2. Android之LinearLayout布局下怎么让按钮固定在底部

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  3. Python开发【第六篇】: 面向对象

    内容概要 面向对象和面向过程 面向对象三大特征 面向对象的成员 类与类之间的关系 约束 type.issubclass.isinstance self.super.MRO 1. 面向对象和面向过程 0 ...

  4. Python开发【第四篇】: 三大器和内置函数

    内容概要 函数名 闭包 迭代器 生成器 推导式与表达式 内置函数 装饰器 初识递归 1.函数名 函数名的运用: 函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量. 01. 函数名的 ...

  5. 【半小时大话.net依赖注入】(一)理论基础+实战控制台程序实现AutoFac注入

    系列目录 第一章|理论基础+实战控制台程序实现AutoFac注入 第二章|AutoFac的常见使用套路 第三章|实战Asp.Net Framework Web程序实现AutoFac注入 第四章|实战A ...

  6. 一篇文章让你理解Ceph的三种存储接口(块设备、文件系统、对象存储)

    “Ceph是一个开源的.统一的.分布式的存储系统”,这是我们宣传Ceph时常说的一句话,其中“统一”是说Ceph可以一套存储系统同时提供块设备存储.文件系统存储和对象存储三种存储功能.一听这句话,具有 ...

  7. hive 之 Cube, Rollup介绍

    1. GROUPING SETS GROUPING SETS作为GROUP BY的子句,允许开发人员在GROUP BY语句后面指定多个统维度,可以简单理解为多条group by语句通过union al ...

  8. 跟我学SpringCloud | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪

    SpringCloud系列教程 | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪 Springboot: 2.1.6.RELEASE SpringCloud: ...

  9. Java程序运行原理分析

    class文件内容 class文件包含Java程序执行的字节码 数据严格按照格式紧凑排列在class文件的二进制流,中间无分割符 文件开头有一个0xcafebabe(16进制)特殊的标志 JVM运行时 ...

  10. centos下安装色彩scrapy

    一.安装Python2.7.6 更新CentOS lib库文件 yum -y update 安装开发工具包 yum groupinstall -y development 安装扩展包 yum inst ...