4 个版本 (2 个重大变更)
0.3.1 | 2021 年 8 月 31 日 |
---|---|
0.3.0 | 2021 年 3 月 10 日 |
0.2.0 | 2020 年 11 月 14 日 |
0.1.0 | 2020 年 10 月 30 日 |
#2292 在 数据结构
89KB
2K SLoC
该包通过绳数据结构的一个变体实现了持久数组。
你为什么需要它?
在 Rust 标准库中,数组作为 std::vec 实现。对于大多数情况,这应该没问题。但是,当我们开始处理超大数组或进入如非破坏性写入和并发访问这样的要求时,我们发现 std::vec 是不够的。《im》是一个流行的替代品,但它对于大型数组来说,insert()
和 delete()
的惩罚类似于 std::vec
。虽然大多数实现更喜欢使用 RRB-Tree,但 ppar
基于绳数据结构 Rope data structure。
以下是一个可能需要使用 ppar
的快速列表。
- 当数组太大且重复插入和删除操作时。
- 当需要共享所有权时。
- 当需要跨并发线程共享所有权时。
- 以支持数组修改的撤销/重做操作。
- 当频繁分割数组或合并数组时。
- 使用写时复制的数组懒加载。
查看我们的 性能指标
算法
基本上,它可以看作是数组块的二叉树,其中每个叶节点是类型 T
的连续块,而中间节点仅持有对子节点的引用 - left
和 right
。更准确地说,树中的中间节点组织方式类似于绳结构,作为 (weight, left, right)
的元组,其中 weight 是左侧分支下叶节点中所有项目之和。
可以在 此处 找到替代方案的列表。如果您找到好的替代方案,请将其添加到列表中并提交 PR。
如果您计划在项目中使用 ppar
,请让我们知道。
目标
- 类型 T 参数化的 Vector。
- 不可变/持久化 Vector 集合。
- CRUD操作,包括get()、set()、delete()、insert(),都是持久的。
- 将Vec转换为ppar::Vector。
- 将ppar::Vector转换为Vec。
- 线程安全的操作。
- 类似于std::vec::Vec的可变API。
- 集合迭代,包括逐项、分块、反向。
- 去重。
- 成员资格。
- 连接集合,拆分集合。
- 部分集合。
- 扩展集合。
- 队列操作,如pop()、push()。
- 函数操作,如filter、map、reduce。
- 排序和搜索操作。
- 特质实现。
- 克隆
- Eq, PartialEq, Ord, PartialOrd
- 扩展
- From, FromIterator, IntoIterator
- 散列
- 索引,索引可变
- 写入
- 使用rayon进行并行迭代。
- 模糊测试。
基本算法相当紧凑。欢迎贡献以使ppar::Vector类型像std::vec::Vec和im::Vector一样丰富。
性能指标
在2008年core2-duo机器上,具有8GB RAM。使用以下命令进行测量,所有数字都是操作Vs延迟。
cargo run --release --bin perf --features=perf -- --load 100000 --ops 10000
数字越低越好
数字越低越好
我们使用初始数据集100_000
u64数字加载数组。然后在一个紧密的循环中应用每个操作,测量整个循环的耗时,最后计算每个操作的延迟。对于迭代,我们计算迭代每个元素的耗时。
- 使用对数刻度表示性能的量级差异。
- 在ppar的arc和rc变体之间,性能差异不大。尽管它可能对缓存优化的算法有影响。
- 对于insert、remove、load、split、append、clone操作,ppar在vec和im上提高了量级的改进。
- 在update、get、iter操作上落后。但值得注意的是,它仍然在日志刻度的较低端,即差异在100ns以内。
值得注意的是,操作的数据集的最大大小小于2MB,这意味着整个数组占位符可以保留在CPU缓存中。根据我的理解,当我们增加数组的大小,性能差异将更加明显,即快速操作可能看起来更快,而慢速操作可能看起来更慢。
有用的链接
贡献
依赖项
~1.3–2.2MB
~49K SLoC