我想要一个功能
-
在堆上分配浮点数的基本变长"array"(在一般意义上,不一定是Rust类型)
-
用值初始化它
-
实现
Drop
,所以我不必担心释放内存 -
实现索引或迭代的东西
显而易见的选择是 Vec
,但它与堆上的盒装切片相比如何呢? Vec
更强大,但我需要数组用于数值计算,在我的情况下,不需要像push / pop这样的东西 . 我们的想法是拥有功能较少但速度更快的东西 .
下面我有两个版本的“linspace”函数(la Matlab和numpy),
-
"linspace_vec"(见下面的清单)使用
Vec
-
"linspace_boxed_slice"(参见下面的清单)使用了一个盒装切片
两者都用得像
let y = linspace_*(start, stop, len);
其中 y
是长度为 len
的线性间隔的"array"(即(1)中的 Vec
和(2)中的盒装切片) .
对于长度为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)
Listing of (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;
}
Listing of (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 回答
在第二个版本中,使用类型
Box<&'a mut [T]>
,这意味着有两个级别的间接达到T
,因为Box
和_2860049都是指针 .你想要的是
Box<[T]>
. 我认为构建这样一个值的唯一合理方法是使用into_boxed_slice方法来自Vec<T>
. 请注意,唯一的好处是您丢失了Vec
将具有的capacity
字段 . 除非您需要在内存中同时拥有大量这些数组,否则开销可能无关紧要 .