Vec和盒装切片的性能比较

时间:2015-11-14 02:42:48

标签: performance rust

我想要一个功能

  • 分配一个基本的可变长度"数组" (在一般意义上的单词,不一定是Rust类型)堆上的浮动
  • 使用值
  • 初始化它
  • 实施Drop,因此我不必担心释放内存
  • 实现索引或迭代的内容

显而易见的选择是Vec,但它与堆上的盒装切片相比如何? Vec更强大,但我需要数组来进行数值计算,在我的情况下,我不需要像推/弹一样的东西。我们的想法是拥有功能较少但速度更快的东西。

下面我有两个版本的" linspace"功能(一个matlab和numpy),

  1. " linspace_vec" (请参阅下面的列表)使用Vec
  2. " linspace_boxed_slice" (见下面的清单)使用盒装切片
  3. 两者都像

    一样使用
    let y = linspace_*(start, stop, len);
    

    其中y是线性间隔的"数组" (即(1)中的Vec和(2)中的方框切片)长度为len

    对于小型阵列"长度为1000,(1)更快。对于长度为4 * 10 ^ 6的大型阵列,(1)为SLOWER。这是为什么?我在(2)做错了吗?

    当参数len = 1000时,仅通过调用函数进行基准测试就会产生

    • (1) ... bench: 879 ns/iter (+/- 12)
    • (2) ... bench: 1,295 ns/iter (+/- 38)

    当参数len = 4000000时,基准测试结果为

    • (1) ... bench: 5,802,836 ns/iter (+/- 90,209)
    • (2) ... bench: 4,767,234 ns/iter (+/- 121,596)

    (1)的清单:

    pub fn linspace_vec<'a, T: 'a>(start: T, stop: T, len: usize) -> Vec<T>
    where
        T: Float,
    {
        // get 0, 1 and the increment dx as T
        let (one, zero, dx) = get_values_as_type_t::<T>(start, stop, len);
        let mut v = vec![zero; len];
        let mut c = zero;
        let ptr: *mut T = v.as_mut_ptr();
        unsafe {
            for ii in 0..len {
                let x = ptr.offset((ii as isize));
                *x = start + c * dx;
                c = c + one;
            }
        }
    
        return v;
    }
    

    (2)的清单:

    pub fn linspace_boxed_slice<'a, T: 'a>(start: T, stop: T, len: usize) -> Box<&'a mut [T]>
    where
        T: Float,
    {
        let (one, zero, dx) = get_values_as_type_t::<T>(start, stop, len);
        let size = len * mem::size_of::<T>();
        unsafe {
            let ptr = heap::allocate(size, align_of::<T>()) as *mut T;
            let mut c = zero;
            for ii in 0..len {
                let x = ptr.offset((ii as isize));
                *x = start + c * dx;
                c = c + one;
            }
            // IS THIS WHAT MAKES IT SLOW?:
            let sl = slice::from_raw_parts_mut(ptr, len);
            return Box::new(sl);
        }
    }
    

1 个答案:

答案 0 :(得分:18)

在您的第二个版本中,您使用Box<&'a mut [T]>类型,这意味着有两个级别的间接达到T,因为Box&都是指针

您想要的是Box<[T]>。我认为构建这样一个值的唯一合理方法是使用into_boxed_slice方法从Vec<T>开始。请注意,唯一的好处是您丢失了capacity所拥有的Vec字段。除非您需要在内存中同时拥有大量这些数组,否则开销可能无关紧要。

pub fn linspace_vec<'a, T: 'a>(start: T, stop: T, len: usize) -> Box<[T]>
where
    T: Float,
{
    // get 0, 1 and the increment dx as T
    let (one, zero, dx) = get_values_as_type_t::<T>(start, stop, len);
    let mut v = vec![zero; len].into_boxed_slice();
    let mut c = zero;
    let ptr: *mut T = v.as_mut_ptr();
    unsafe {
        for ii in 0..len {
            let x = ptr.offset((ii as isize));
            *x = start + c * dx;
            c = c + one;
        }
    }

    v
}