我是否必须担心“Rc”的开销?

时间:2015-07-07 09:24:38

标签: rust

我是否正确地假设“减慢”Rc的唯一事情是它检查是否在对象掉落时解除分配?除此之外,取消引用Rc的开销“多少”,即我应该关注它吗?
这两个功能几乎同样快吗?或者速度有明显差异吗?

fn test_with_box() {
    let b = Box::new(1.0);
    let x = b * 2;
}

fn test_with_rc() {
    let rc = Rc::new(1.0);
    let x = rc * 2;
}

由于test_with_rc()中引用的对象始终只有一个引用,并且在该函数中的行为类似于Box(当然,从外部查看,而不是在内部查看)。

我怀疑Rc实际上比我想象的要快。

PS:在谈论“快速”时,我的意思是解除引用和分配/解除分配。

2 个答案:

答案 0 :(得分:9)

Rc<T>非常非常便宜。它并不像T那么便宜(拳击值在微优化术语中比较昂贵),但效率几乎没有Box<T>

就像Box一样,但是对于强弱引用计数还有一些单词,而且需要触及的唯一事情是创建Rc(初始化值),克隆Rc(递增引用计数)并删除Rc(如果合适,递减引用计数并运行析构函数)。在不稳定的代码中,还会从Weak降级/升级(同样琐碎的东西)。

解除引用是一种简单的内存操作,就像使用Box一样。

答案 1 :(得分:8)

要回答您的问题,您可以转到test包,其中包含基准测试解决方案(这需要每晚一次):

#![feature(test)]
extern crate test;

use std::rc::Rc;

fn test_with_box() {
    let b = Box::new(1.0);
    test::black_box(*b * 2.0);
}

fn test_with_rc() {
    let rc = Rc::new(1.0);
    test::black_box(*rc * 2.0);
}

#[bench]
fn bench_box(b: &mut test::Bencher) {
    b.iter(test_with_box)
}

#[bench]
fn bench_rc(b: &mut test::Bencher) {
    b.iter(test_with_rc)
}

现在正在编译&amp;运行这个:

$ rustc --test -O rc.rs && ./rc --bench

running 2 tests
test bench_box ... bench:          22 ns/iter (+/- 0)
test bench_rc  ... bench:          22 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured

发生什么事了? RC显然是完全编译出来的。应该是这样,因为我们没有克隆它。因此,将相应的fn更改为:

fn test_with_rc() {
    let rc = Rc::new(1.0);
    test::black_box(*rc.clone() * 2.0);
}

我们得到以下信息:

running 2 tests
test bench_box ... bench:          23 ns/iter (+/- 1)
test bench_rc  ... bench:          25 ns/iter (+/- 1)

test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured

因此,足以说明,在考虑RC引起的开销之前,您可能需要担心其他事情。

相关问题