3个版本 (1个稳定版本)
2.2.3 | 2022年10月16日 |
---|---|
0.1.1 | 2022年10月10日 |
0.1.0 | 2022年10月9日 |
#906 in 编码
74KB
1.5K SLoC
并发哈希表。
这是对 https://gitlab.redox-os.org/redox-os/chashmap 的克隆,当时似乎没有太多维护。 我并不认为原始作者的辛勤工作应该得到认可。 我的贡献是添加serde支持以及我可能需要的其他功能。
该crate实现了基于桶级别多读锁的并发哈希表,具有卓越的性能特征¹,并支持调整大小、原地修改等。
API直接从 std::collections::HashMap
继承而来,使其感觉非常熟悉。
¹请注意,它很大程度上依赖于您程序的行为,但在大多数情况下,它非常好。在某些(罕见)情况下,您可能需要原子哈希表。
工作原理
chashmap
不是无锁的,但它将锁分布在整个映射中,使得锁竞争(这可能会使访问变得昂贵)非常罕见。
哈希表由所谓的“桶”组成,每个桶定义了表中的潜在条目。某些键值对的桶由键的哈希值确定。通过为每个桶保持读写锁,我们确保您通常只需一个或两个锁定子程序即可插入、读取、修改等。
特殊情况:重新分配。当表被填满,几乎没有空闲桶(注意,这“几乎没有”而不是“没有”,因为负载因子不应太高,因为这会损害性能)时,在重新散列表时获得全局锁。这非常低效,但这种情况很少发生,并且由于容量具有适应性,当映射刚刚初始化时,它只会发生几次。
冲突解决
当两个哈希值发生冲突时,它们不能共享同一个桶,因此必须有一个算法可以解决冲突。在我们的情况下,我们使用线性探测,这意味着我们取紧随其后的桶,并重复直到找到空闲的桶。
这种方法远非理想,但像Robin-Hood哈希这样的更优方法在并发结构中效果不佳(如果有的话)。
API
如果您熟悉libstd哈希表实现,那么API应该感觉非常熟悉。它们共享许多方法,并且我已经仔细确保所有在libstd中有相似名称的项目在语义和行为上是一致的。
Serde
已添加对Serde的支持,并应与您选择的任何Serde序列化器/反序列化器一起工作。
fn main() {
//================================================================================
// serialize
//================================================================================
let cmap1 = CHashMap::<String, String>::new();
cmap1.insert("key1".to_string(), "val1".to_string());
cmap1.insert("key2".to_string(), "val2".to_string());
let j1 = serde_json::to_string(&cmap1);
assert!(j1.is_ok());
//================================================================================
// deserialize
//================================================================================
let j1 = j1.unwrap();
let cmap1x: CHashMap<String, String> = serde_json::from_str(j1.as_str()).unwrap();
assert_eq!(*cmap1.get("key1").unwrap(), *cmap1x.get("key1").unwrap());
assert_eq!(*cmap1.get("key2").unwrap(), *cmap1x.get("key2").unwrap());
}
依赖项
~0.9–6.5MB
~36K SLoC