我想要一个函数

  • 在堆上分配浮点数的基本可变长度"数组"(一般意义上,不一定是 rust 类型)
  • 用值初始化它
  • 实现Drop,所以我不必担心释放内存
  • 实现一些用于索引或迭代的东西

显而易见的 Select 是Vec,但它与堆上的盒装切片相比如何?Vec更强大,但我需要用于数值计算的数组,在我的情况下,不需要push/pop之类的东西.这样做的目的是让功能更少,但速度更快.

下面我有两个版本的"linspace"函数(la Matlab和numpy),

  1. "linspace_vec"(见下表)使用Vec
  2. "linspace_boxed_slice"(见下面的 list )使用一个boxed slice

两者都像

let y = linspace_*(start, stop, len);

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

对于长度为1000的小型"数组",则(1)更快.对于长度为4*10^6的大型数组,(1)较慢.为什么?我在第(2)项中做错了什么吗?

当参数len=len0时,仅通过调用函数进行基准测试会导致

  • (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);
    }
}

推荐答案

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

你想要的是Box<[T]>.我认为构造这样一个值的唯一合理方法是从Vec<T>开始,使用into_boxed_slice方法.请注意,唯一的好处是您失go 了Vec将拥有的capacity字段.除非您需要同时在内存中存储很多这样的数组,否则开销可能很小.

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
}

Rust相关问答推荐

为什么幻影数据不能自动推断?

当Option为None时,Option数组是否占用Rust中的内存?

MacOS(AARCH64)上Ghidra中的二进制补丁导致进程终止

为什么我不能从带有字符串的 struct 的引用迭代器中收集VEC<;&;str&>?

如何使用reqwest进行异步请求?

用于实现获取 struct 体 id 的特征规范

如何从宏调用闭包?

RUST 中的读写器锁定模式

使用启用优化的 alloc 会导致非法指令崩溃

从 rust 函数返回 &HashMap

在 Rust 中查找向量中 dyn struct 的索引

在1.5n次比较中找到整数向量中的最大和次大整数

我什么时候应该使用特征作为 Rust 的类型?

在运行时在 Rust 中加载字体

在异步 Rust 中,Future 如何确保它只调用最近的 Waker?

当 T 不是副本时,为什么取消引用 Box 不会抱怨移出共享引用?

如何将切片推入数组?

提取 struct 生成宏中字段出现的索引

相互调用的递归异步函数:检测到循环

Rust 生命周期:不能在方法内重新borrow 可变字段