【发布时间】:2016-02-15 17:37:07
【问题描述】:
我想要一个函数来
- 在堆上分配一个基本的可变长度“数组”(一般意义上,不一定是 Rust 类型)的浮点数
- 用值初始化它
- 实现
Drop,这样我就不用担心释放内存了 - 为索引或迭代实现一些东西
显而易见的选择是Vec,但它与堆上的盒装切片相比如何? Vec 更强大,但我需要用于数值数学的数组,并且在我的情况下,不需要像 push/pop 这样的东西。我们的想法是拥有更少功能但更快的东西。
下面我有两个版本的“linspace”函数(一个 la Matlab 和 numpy),
- “linspace_vec”(参见下面的列表)使用
Vec - “linspace_boxed_slice”(参见下面的清单)使用盒装切片
两者都像
let y = linspace_*(start, stop, len);
其中y 是长度为len 的线性间隔“数组”(即(1)中的Vec 和(2)中的盒装切片)。
对于长度为 1000 的小型“数组”,(1) 更快。对于长度为 4*10^6 的大型数组,(1) 更慢。这是为什么?我在 (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);
}
}
【问题讨论】:
-
如果我理解这个功能,不要认为你需要降到那个级别才能快速运行。迭代器非常棒:bench: 2,755,606 ns/iter (+/- 408,352).
标签: performance rust