1 个不稳定版本
0.1.0 | 2022年2月16日 |
---|
#736 in 并发
18KB
175 行
shardize
关于是否可以使用宏来创建现有容器的分片形式的实验。
如果可行,这将允许我们在多线程场景中减少竞争,通过确保锁(或对无锁资源的竞争)仅应用于单个分片而不是整个容器。
性能
在一个非常简单的测试中,我们比较了以下两个结构
let m1 = Mutex::new(HashMap::<usize, String>::new());
和
let m2 = ShardedMutexHashmap::<Mutex<HashMap<usize, String>>, 10>::new(&my_shard_key);
m2
是一个具有与 m1
相同的 get
和 set
方法的容器,但其底层实现使用 10 个不同的 HashMap
,每个都位于自己的 Mutex
中。
当我们启动 10 个线程并向 m1
和 m2
中写入 1000 个值时,我们可以看到 m2
的性能要快得多
$ cargo bench
...
test read_from_mutex_hashmap ... bench: 1,032,460 ns/iter (+/- 835,085)
test read_from_sharded_mutex_hashmap ... bench: 302,203 ns/iter (+/- 22,340)
test write_to_mutex_hashmap ... bench: 1,221,228 ns/iter (+/- 1,394,711)
test write_to_sharded_mutex_hashmap ... bench: 378,115 ns/iter (+/- 21,017)
如何使用
为了能够像上面那样使用 ShardedMutexHashmap
,我们需要提供以下代码
#[shardize(ShardedMutexHashmap)]
trait MyTrait: Default {
fn get(&self, key: usize) -> String;
fn set(&self, key: usize, value: String);
}
impl MyTrait for Mutex<HashMap<usize, String>> {
fn get(&self, key: usize) -> String {
self.lock().unwrap().get(&key).unwrap().clone()
}
fn set(&self, key: usize, value: String) {
self.lock().unwrap().insert(key, value);
}
}
fn my_shard_key(key: usize) -> usize {
key
}
ShardedMutexHashmap
是由 shardize
宏根据 MyTrait
和 MyTrait
的实现生成的。生成的代码为每个分片创建底层容器(这里是一个 Mutex<HashMap<...>>
)的一个副本,并从适当的分片中存储/检索值,它通过在 get
或 set
中传入的键上调用 my_shard_key
来找到它。
许可证
版权所有 2022 年 John Bell 和 Andy Balaam,根据您选择的 Apache 许可证,版本 2.0 或 MIT 许可证。
行为准则
请注意,本项目遵循 贡献者行为准则。通过参与本项目,您同意遵守其条款。
依赖关系
~1.5MB
~35K SLoC