cython中实现的快速、可重入乐观锁
fastrlock的Python项目详细描述
快速锁定
这是cpython快速、可重入、乐观锁的c级实现。 这是一个替代品 threading.RLock。 fastrlock在Cython中实现,还提供了一个c-api 从cython代码通过from fastrlock cimport rlock直接使用。
在正常情况下,它比Python2.7中的threading.rlock快10倍。 因为它避免了所有的锁定,除非两个或多个线程尝试在 同时。在拥挤的情况下,它仍然比rlock快10%左右,因为 在cython中实现。
这基本上相当于python 3.2中修改过的rlock实现, 但由于在cython中实现,速度更快。但是,在python 3.4和 稍后,stdlib中的threading.RLock实现往往同样快 或者甚至比这个包提供的锁更快,当通过 python api。FastRLock在这些系统上调用时仍然更快 通过其他cython模块的cython api。
最初在这里作为代码配方发布: https://code.activestate.com/recipes/577336-fast-re-entrant-optimistic-lock-implemented-in-cyt/
fastrlock已经在Lupa中使用和测试了好几年。
它是如何工作的?
fastrlock实现可针对非拥塞情况进行优化。它的工作原理是 利用gil的可用性。因为它知道当 调用了acquire()/release()方法,它可以安全地检查锁 由其他线程持有,只要总是 获取它的同一线程。这比实际获得 底层锁。
当第二个线程也想获取锁时,它首先检查锁 数一数,发现锁已经被拥有了。如果底层锁也是 已经被另一个线程持有,然后它释放gil并请求获得 锁,就像rlock一样。但是,如果未持有基础锁,则 通过告知 现在的主人可以在完成后释放它。然后,它又回到了正常状态 要求锁的非所有者行为,并最终在锁 被释放。这确保只有在至少 两条线需要它。
所有这些操作基本上都是原子的,因为任何修改 锁定状态始终保持gil。注意,实现不能调用任何 处理锁时的python代码,因为调用python可能会导致上下文 把gil交给另一个线程,从而打破原子性。 因此,代码错误地使用了cython的“nogil”注释,以确保没有python 代码意外插入。
有多快?
以下是Python2.7在以下情况下的一些计时:
- 五个获取释放周期(“锁定解锁”)
- 五个acquire调用,然后是五个release调用(嵌套锁,“可重入锁”unlock“)
- 一个混合和部分嵌套的获取和释放调用序列(“mixed_lock_unlock”)
- 五个不阻塞的获取释放周期(“锁定/解锁/非阻塞”)
所有四个都是针对单线程和多线程情况进行基准测试的 有10根线。我还用20个线程测试了它,结果发现 两个版本的时间大约是两倍。还要注意,拥挤的情况是 两个锁的速度都要慢得多,所以我在这里只循环了1000次 单螺纹壳体的计时而不是100000倍。
Testing threading.RLock sequential (x100000): lock_unlock : 1.408 sec reentrant_lock_unlock : 1.089 sec mixed_lock_unlock : 1.212 sec lock_unlock_nonblocking : 1.415 sec threaded 10T (x1000): lock_unlock : 1.188 sec reentrant_lock_unlock : 1.039 sec mixed_lock_unlock : 1.068 sec lock_unlock_nonblocking : 1.199 sec Testing FastRLock sequential (x100000): lock_unlock : 0.122 sec reentrant_lock_unlock : 0.124 sec mixed_lock_unlock : 0.137 sec lock_unlock_nonblocking : 0.156 sec threaded 10T (x1000): lock_unlock : 0.911 sec reentrant_lock_unlock : 0.938 sec mixed_lock_unlock : 0.953 sec lock_unlock_nonblocking : 0.916 sec
与Python3.2及更高版本相比如何?
下面是使用py3.2运行的相同基准:
Testing threading.RLock sequential (x100000): lock_unlock : 0.134 sec reentrant_lock_unlock : 0.120 sec mixed_lock_unlock : 0.151 sec lock_unlock_nonblocking : 0.177 sec threaded 10T (x1000): lock_unlock : 0.885 sec reentrant_lock_unlock : 0.972 sec mixed_lock_unlock : 0.883 sec lock_unlock_nonblocking : 0.911 sec Testing FastRLock sequential (x100000): lock_unlock : 0.093 sec reentrant_lock_unlock : 0.093 sec mixed_lock_unlock : 0.104 sec lock_unlock_nonblocking : 0.112 sec threaded 10T (x1000): lock_unlock : 0.943 sec reentrant_lock_unlock : 0.871 sec mixed_lock_unlock : 0.920 sec lock_unlock_nonblocking : 0.908 sec
因此,在单线程的情况下,py3.2中的c实现仅为 大约比cython实现慢20-50%,然而 在拥挤的情况下,速度差不多。
快速锁定更改日志
0.4(2018-08-24)
- 用cython 0.28.5重建。
- 通过配置文件引导的优化,Linux控制盘速度更快。
- 将缺少的文件添加到sdist。 (由Mark Harfouche修补,Github第5期)
0.3(2017-08-10)
- 改进c-api的cimport支持 (由naotoshi seo提供补丁,github问题3)
- 提供fastrlock.__version__
0.2(2017-08-09)
- 将缺少的自述文件添加到sdist
0.1(2017-06-04)
- 初始版本