10个版本 (5个重大更改)
0.6.1 | 2023年10月2日 |
---|---|
0.6.0 | 2023年4月2日 |
0.5.1 | 2023年3月30日 |
0.5.0 | 2021年3月14日 |
0.1.0 | 2020年6月9日 |
#260 in Rust模式
717 每月下载量
在 8 个crate中使用 (直接使用3个)
54KB
1K SLoC
基于原子引用计数的interner库
文档请见 docs.rs.
在开发过程中请使用 cargo bench
和 cargo +nightly miri
—多线程测试大小适中,在运行miri(运行速度较慢)时会暴露问题。一旦发现问题,使用以下方式调试会更简单:
export MIRIFLAGS=-Zmiri-disable-isolation
cargo +nightly miri test --features println -- --nocapture multithreading_hash
另一个非常有用的工具是 loom,运行它:
LOOM_LOG=1 LOOM_LOCATION=1 LOOM_CHECKPOINT_INTERVAL=1 RUST_BACKTRACE=1 RUSTFLAGS="--cfg loom" cargo test --lib
注意: loom
目前无法工作,因为它不支持弱引用。
许可证
根据您的选择:Apache-2.0或MIT
lib.rs
:
基于原子引用计数的interner库
此库与arc-interner
(其作为初始灵感来源)不同之处在于
- interner必须创建并可以销毁(有关方便函数,请参见下面)
- 它不基于
TypeId
调度(每个interner针对 exactly one type) - 它提供基于
Hash
和Ord
的存储 - 它处理无尺寸类型时没有开销,因此您应该内联
str
而不是String
不幸的是,这个功能组合使得使用不安全的Rust成为不可避免。未大小值构造已从标准库的Arc
类型中借鉴;引用计数使用parking_lot
互斥锁,因为它还必须确保对将值从其内部存储中删除的清理函数的一致访问和使用。测试套件在miri下也能通过,以检查不安全代码中的一些未定义行为(包括内存泄漏)。
API版本
相同的API提供了两种版本
HashInterner
使用基于哈希的存储,即标准的HashSet
OrdInterner
使用基于顺序的存储,即标准的BTreeSet
在典型的服务器CPU上,小值内部化的时间大约为100-200纳秒。当内部化大值(如大于1KB的切片)时,基于顺序的存储具有优势。当同时内部化大量值(数千个或更多)时,基于哈希的存储具有优势。
然而,没有什么能比得上你自己的基准测试。
便捷访问内部化器
例如,在专用反序列化线程中使用内部化时,最好创建并局部使用内部化器,避免进一步的同步开销。如果你只关心每个线程的重复数据删除,也可以将内部化器存储在线程局部变量中。
话虽如此,这个crate还提供了基于全局类型索引池的便捷函数
use intern_arc::{global::hash_interner};
let i1 = hash_interner().intern_ref("hello"); // -> InternedHash<str>
let i2 = hash_interner().intern_sized(vec![1, 2, 3]); // -> InternedHash<Vec<i32>>
你也可以自己使用类型索引池来控制其生命周期
use intern_arc::{global::OrdInternerPool, InternedOrd};
let mut pool = OrdInternerPool::new();
let i: InternedOrd<[u8]> = pool.get_or_create().intern_box(vec![1, 2, 3].into());
依赖
~0.4–25MB
~345K SLoC