Rc: 一个数据多个所有者
RefCell: 修改数据
//千万不要引用错包
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let s = Rc::new(RefCell::new("我很善变,还有多个主人".to_string()));
let s1 = s.clone();
let s2 = s.clone();
s2.borrow_mut().push_str(",oh hh");
println!("{:?}\n {:?} \n {:?} ", s, s1, s2);
}
//no method named `push_str` found for mutable reference `&mut Rc<RefCell<&str>>` in the current scope
性能损耗
性能其实非常高,大致相当于没有线程安全版本的 C++ std::shared_ptr 指针,事实上,C++ 这个指针的主要开销也在于原子性这个并发原语上,毕竟线程安全在哪个语言中开销都不小。内存损耗
两者结合的数据结构与下面类似
struct Warapper<T>{
//Rc
strong_count:usize,
weak_count:usize,
//RefCell
borrow_count:isize,
//包裹的数据
item:T,
}
也就是多了三个size
CPU损耗
- 对Rc解引用是免费的(编译器) ,但是*带的间接取值并无免费
- 克隆Rc需要当前的引用计数跟0和usize::max进行一次比较,然后加1
- 释放drop Rc需要计数减一 然后跟0进行一次比较
- 对Refcell进行不可变借用,需要将isze类型的借用计数加1,然后跟0比较
- 对RefCell的不可变借用进行释放,需要将isize减1
- 对RefCell的可变借用大致流程跟上面差不多 ,但是需要先跟0比较再减1
- 对RefCell的可变借用进行释放,需要将size加1
总结Cpu消耗非常低,设置编译器还会对此进行进一步优化
CPU 缓存 Miss
唯一需要担心的可能就是这种组合数据结构对于 CPU 缓存是否亲和,这个我们无法证明,只能提出来存在这个可能性,最终的性能影响还需要在实际场景中进行测试。 总之,分析这两者组合的性能还挺复杂的,大概总结下:- 从表面来看,它们带来的内存和 CPU 损耗都不大
- 但是由于 Rc 额外的引入了一次间接取值(*),在少数场景下可能会造成性能上的显著损失
- CPU 缓存可能也不够亲和