#map #hash-map #syn #read-write #disjoint-set #constant-time

syncmap

syncmap 是一个以性能和正确性为重点的快速并发缓存库。构建 syncmap 的动机来自 Golang 中的 sync.Map

3 个版本

0.1.3 2022 年 11 月 30 日
0.1.2 2022 年 11 月 29 日
0.1.1 2022 年 11 月 28 日

#969 in 并发

MIT 许可证

37KB
671

syncmap

syncmap

syncmap 是一个快速并发缓存库

syncmap 是一个以性能和正确性为重点的快速并发缓存库。

构建 syncmap 的动机来自 Golang 中的 sync.Map。

摘要

Map 类似于哈希表,但可以在不使用额外锁定或协调的情况下安全地由多个线程并发使用。加载、存储和删除操作运行在摊销常数时间内。

Map 类型是专业的。大多数代码应该使用普通的 Rust HashMap,并单独进行锁定或协调,以获得更好的类型安全,并使维护其他不变性以及映射内容更容易。

Map 类型针对两种常见用例进行了优化:(1) 当给定键的条目只写一次但读取多次时,如只增长的缓存,或(2) 当多个线程读取、写入和覆盖不相交键集的条目时。在这两种情况下,使用 Map 可能会显著减少与 Rust HashMap 配对的单独 Mutex 或 RWMutex 的锁定竞争。

零 Map 是空的,并准备好使用。Map 必须在使用后不得复制。

在 Go 内存模型的术语中,Map 安排写操作“在”任何观察到写操作效果的读操作之前“同步”。以下是读操作和写操作的定义:加载、LoadAndDelete、LoadOrStore 是读操作;Delete、LoadAndDelete 和 Store 是写操作;LoadOrStore 在返回加载设置为 false 时是写操作。

状态

syncmap 可以使用,但仍在积极开发中。我们预计它将在不久的将来准备好用于生产。

使用方法

示例

// concurrent exmaple
 use syncmap::map::Map;
fn main() {
 let map = Arc::new(Map::<usize, usize>::new());

 let map1 = map.clone();
 let t1 = std::thread::spawn(move || {
  for i in 0..5000 {
   map1.insert(i, 0, &map1.guard());
  }
 });
 let map2 = map.clone();
 let t2 = std::thread::spawn(move || {
  for i in 0..5000 {
   map2.insert(i, 1, &map2.guard());
  }
 });

 t1.join().unwrap();
 t2.join().unwrap();

 thread::sleep(Duration::from_micros(1000));
 let mut missed = 0;
 let guard = map.guard();
 for i in 0..5000 {
  let v = map.get(&i, &guard);
  if v.is_some() {
   assert!(v == Some(&0) || v == Some(&1));
  } else {
   missed += 1;
  }

  // let kv = map.get_key_value(&i, &guard).unwrap();
  // assert!(kv == (&i, &0) || kv == (&i, &1));
 }
 println!("missed {}", missed)
}
 use syncmap::map::Map;
fn main() {
  let cache = Map::new();

  let guard = cache.guard();
  cache.insert("key", "value1",  &guard);
 
  thread::sleep(Duration::from_millis(50));

  assert_eq!(cache.get(&"key", &guard), Some("value1"));

}

依赖项

~5–11MB
~105K SLoC