#性能 # #向量 #内联 #无 std #内存管理

无 std stackvec

一个用于使用栈分配向量的 crate(性能和/或无 std)

5 个不稳定版本

使用旧的 Rust 2015

0.2.1 2018 年 11 月 11 日
0.1.1 2018 年 11 月 4 日
0.1.0 2018 年 11 月 4 日
0.0.2 2018 年 11 月 1 日
0.0.1 2018 年 10 月 28 日

2520Rust 模式 中排名

Download history 9/week @ 2024-01-08 1/week @ 2024-01-15 45/week @ 2024-02-19 24/week @ 2024-02-26 22/week @ 2024-03-04 48/week @ 2024-03-11 20/week @ 2024-03-18

每月 117 次下载

MIT 许可证

3MB
850

包含 (ELF 可执行文件/库, 7.5MB) kcov/kcov, (ELF 库, 1MB) kcov/libbfd-2.25-system.so, (ELF 库, 1.5MB) kcov/libopcodes-2.25-system.so

[;向量]

一个 Rust crate,用于使用栈分配向量(以提高性能或在没有 std 的情况下使用)

Repository Latest version Documentation

Travis-CI Status Test code coverage License

动机

Rust 的 栈/内联数组 没有实现 2 个非常有用的与 迭代器相关接口

  1. IntoIterator<Item = T> for [T;n]

    • 允许使用 .into_iter() 代替 .iter().cloned()(实际上,只能在 T: Clone 的情况下使用,并且需要复制,这可能会很昂贵)
    • extern crate stackvec; use ::stackvec::prelude::*;
      
      fn main ()
      {
          // An array of vectors (potentially expensive to clone)
          let vecs_array = [
              vec![1, 2, 3, 4],
              vec![],
              vec![5, 6],
          ];
      
          // Collect / chain all the vectors together
          let flattened: Vec<u8> = vecs_array
                                      .into_iter()  // Needs stackvec (line 1)
                                      .flatten()
                                      .collect()
          ;
          assert_eq!(flattened, vec![1, 2, 3, 4, 5, 6]);
      }
      
  2. FromIteratorfor [T;n]

    • 允许将 collect 收集到 array
    • 由于不完整的数组是不可靠的,当迭代器没有足够的元素填充数组时,收集会失败。因此,引入了新的 TryFromIterator 特性(提供 try_collect)。
    • extern crate stackvec; use ::stackvec::prelude::*;
      
      fn main ()
      {
          let array: [_; 3] = [1, 2, 3];
      
          let doubled: [_; 3] = array
                                  .iter()
                                  .map(|&x| 2 * x)
                                  .try_collect() // Needs stackvec (line 1)
                                  .expect("Missing elements to collect")
          ;
          assert_eq!(doubled, [2, 4, 6]);
      } 
      

原因在于这两个接口都需要一个能够存储部分迭代状态的结构:即不完整的数组。它们具有(静态分配的)可能未初始化的内存:因此,它们在某种程度上类似于 Vec(除了它们的(初始)容量是固定的且不能更改之外)

这就是为什么拥有那些优秀的迭代器 接口需要编写一个与Vec'的内存所有权管理逻辑非常相似的插槽精确逻辑:因此才有StackVec

附加说明

通过公开上述接口所需的底层StackVec,我们能够完全访问一个堆栈分配的Vec,它本身也可能很有用,因为它避免了堆分配

  • 堆是一个可变的全局状态,在多线程环境中涉及锁

  • 它可能需要(缓慢的)系统分配

  • 堆分配并不总是可用

免责声明

使用StackVec而不是Vec带来的性能提升并不总是保证,因为

  1. Vec是Rust std库集合的基石,其代码被编写得非常高效,以便LLVM可以轻松优化其使用

  2. Rust的分配器也进行了非常出色的优化,因此bins管理和系统分配(以及在多线程环境中的锁)的性能惩罚在平均情况下得到了很好的摊销。

VecStackVec基本基准测试

$ cargo +nightly bench --features nightly

test vec_extend             ... bench:      64,129 ns/iter (+/- 3,069)
test vec_from_iter          ... bench:      65,569 ns/iter (+/- 3,761)
test array_from_iter        ... bench:     358,993 ns/iter (+/- 6,916)
test stackvec_extend        ... bench:     360,105 ns/iter (+/- 17,489)
test stackvec_from_iter     ... bench:     369,585 ns/iter (+/- 40,894)
test stackvec_extend_by_ref ... bench:     374,226 ns/iter (+/- 11,686)
test vec_extend_by_ref      ... bench:     863,362 ns/iter (+/- 32,483)

使用方法

  • 将此行添加到您的Cargo.toml(在[dependencies]下)

    stackvec = "0.2.1"
    
    • 注意:默认情况下,stackvec改进所有小于1000个元素的数组。这会导致编译时间更长。如果这是一个问题,并且您并不真的打算使用任意长度的数组,而是使用100的固定倍数或2的幂,您可以使用以下行依赖一个“更轻”的stackvec
      stackvec = { version = "0.2.1", default-features = false }
      
  • 将此添加到您的.rs代码

    extern crate stackvec;
    
    use ::stackvec::prelude::*;
    

示例

查看示例的源代码(链接)

您可以使用以下命令运行每个示例(example_name.rs

$ cargo run --example example_name

进行中

  1. no_std支持

  2. 更多Vec-类似的方法(链接)

无运行时依赖

特性