3 个不稳定版本
0.2.5 | 2021年4月14日 |
---|---|
0.2.0 | 2021年4月14日 |
0.1.0 | 2021年4月12日 |
1338 在 数据结构 中
每月40次下载
1MB
390 行
乐观锁耦合
来自论文 "乐观锁耦合:一种可扩展且高效的通用同步方法"
在实际项目中,当存在许多写冲突时,有一些无锁数据结构,特别是数据库相关的,如 BwTree
,Split-Ordered List
(也称为无锁哈希表)。性能损失非常严重,有时甚至不如无脑 Mutex。然而,无脑 Mutex 在正常情况下性能通常很差,那么是否存在一种折中的形式可以解决这个问题?
这就是折中的形式。因此,它可以用作通用锁,并且性能令人满意。
但是,我有一个设计良好且针对使用场景进行了优化的无锁数据结构。它不能成为你的实现吗?
当然,这更好,但你没有114514 PHD学生来优化你的数据结构,也没有1919810位强大的调试大师来处理内存顺序等问题,这会变得棘手。
这时,我的项目已经上线,投资者已经给了我钱。
那么这种数据结构的缺点是什么?
当然有~
这种数据结构的缺点主要在于使用了61位版本,当这个版本满时,我们就可以躺平了。当然,如果你的数据结构疯狂地改变到这个二进制,你应该在写代码时遇到问题。
基准测试
源代码位于 \benches
目录下。你可以在自己的机器上运行它~
在 my MacOS 2.3 GHz Intel Core i5 上的基准测试结果
- 重读
- 重写
- 只读
- 只写
缺点
乐观锁的缺点很明显。当存在严重冲突时,它会被 Mutex 和其他锁机制撞得粉碎。但当 读 > 写 时,乐观锁表现得更好。
锁的使用
当有3个读取核心和2个写入核心时
移除阻塞日志的中间部分
操作 | Delta 时间 | 线程ID | 状态 |
---|---|---|---|
读取 | 142869 | 线程ID(6) | OptimisticLockCouplingReadGuard { version: 0, data: 1 } |
ErrRead | 216320 | 线程ID(6) | 同步失败 |
ErrRead | 222578 | 线程ID(6) | 阻塞 |
ErrRead | 241218 | 线程ID(6) | 阻塞 |
写入 | 145456 | 线程ID(2) | OptimisticLockCouplingWriteGuard { version: 0, data: 1 } |
写入 | 291942 | 线程ID(2) | OptimisticLockCouplingWriteGuard { version: 1, data: 2 } |
写入 | 312349 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 2, 数据: 3 } |
写错误 | 147945 | 线程ID(3) | 阻塞 |
写错误 | 530522 | 线程ID(3) | 阻塞 |
写入 | 319592 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 3, 数据: 4 } |
写入 | 548172 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 4, 数据: 5 } |
写入 | 605291 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 5, 数据: 6 } |
写入 | 613679 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 6, 数据: 7 } |
写入 | 618416 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 7, 数据: 8 } |
写入 | 623453 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 8, 数据: 9 } |
写入 | 627723 | 线程ID(2) | 乐观锁耦合写保护 { 版本: 9, 数据: 10 } |
写错误 | 536923 | 线程ID(3) | 阻塞 |
写入 | 696435 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 10, 数据: 11 } |
写入 | 704458 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 11, 数据: 12 } |
写入 | 712664 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 12, 数据: 13 } |
写入 | 718093 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 13, 数据: 14 } |
写入 | 749839 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 14, 数据: 15 } |
写入 | 755558 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 15, 数据: 16 } |
ErrRead | 149826 | 线程ID(5) | 阻塞 |
ErrRead | 805119 | 线程ID(5) | 阻塞 |
ErrRead | 810206 | 线程ID(5) | 阻塞 |
写入 | 775039 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 16, 数据: 17 } |
写入 | 871475 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 17, 数据: 18 } |
写入 | 891289 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 18, 数据: 19 } |
写入 | 896488 | 线程ID(3) | 乐观锁耦合写保护 { 版本: 19, 数据: 20 } |
ErrRead | 273387 | 线程ID(6) | 阻塞 |
读取 | 925559 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 971184 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 994963 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 998833 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1002179 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1005515 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1008870 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
ErrRead | 831229 | 线程ID(5) | 阻塞 |
读取 | 1055143 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1076076 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1080036 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1083564 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1086850 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1090126 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1093422 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1110135 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1115111 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1118556 | 线程ID(5) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1038825 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1142881 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1146449 | 线程ID(6) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
ErrRead | 148865 | 线程ID(4) | 阻塞 |
读取 | 1197872 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1217034 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1220737 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1224141 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1227430 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1230666 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1233888 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1237159 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1240422 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |
读取 | 1243714 | 线程ID(4) | 乐观锁耦合读保护 { 版本: 20, 数据: 20 } |