Python锁机制如何理解,RLock()与Lock()有何不同
Admin 2022-08-03 群英技术资讯 307 次浏览
要回答这个问题,我们需要知道为什么需要使用锁机制。前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享资源时,如果此时没有预设对应的同步机制,就可能带来同一时刻多个线程同时访问同一个共享资源,即出现竞态,多数情况下我们是不希望出现这样的情况的,那么怎么避免呢?
先看一段代码:
import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): resource += 1 def decerment(): global resource for i in range(count): resource -= 1 increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start() increment_thread.join() decerment_thread.join() print(resource)
运行截图如下:
运行结果
当我们多次运行时,可以看到最终的结果都几乎不等于我们期待的值即resource
初始值0
。
为什么呢? 原因就是因为 += 和 -=并不是原子操作。
可以使用dis模块查看字节码:
import dis def add(total): total += 1 def desc(total): total -= 1 total = 0 print(dis.dis(add)) print(dis.dis(desc)) # 运行结果: # 3 0 LOAD_FAST 0 (total) # 3 LOAD_CONST 1 (1) # 6 INPLACE_ADD # 7 STORE_FAST 0 (total) # 10 LOAD_CONST 0 (None) # 13 RETURN_VALUE # None # 5 0 LOAD_FAST 0 (total) # 3 LOAD_CONST 1 (1) # 6 INPLACE_SUBTRACT # 7 STORE_FAST 0 (total) # 10 LOAD_CONST 0 (None) # 13 RETURN_VALUE # None
那么如何保证初始值为0
呢? 我们可以利用Lock()
,代码如下:
import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): resource_lock.acquire() resource += 1 resource_lock.release() def decerment(): global resource for i in range(count): resource_lock.acquire() resource -= 1 resource_lock.release() increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start() increment_thread.join() decerment_thread.join() print(resource)
运行截图如下:
运行结果
从运行结果可以看到,不论我们运行多少次改代码,其resource
的值都为初始值0
, 这就是Lock()
的功劳,即它可以将某一时刻的访问限定在单个线程或者单个类型的线程上,在访问锁定的共享资源时,必须要现获取对应的锁才能访问,即要等待其他线程释放资源,即resource_lock.release()
当然为了防止我们对某个资源锁定后,忘记释放锁,导致死锁,我们可以利用上下文管理器管理锁实现同样的效果:
import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): with resource_lock: resource += 1 def decerment(): global resource for i in range(count): with resource_lock: resource -= 1 increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start()
我们需要知道Lock()
作为一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取,否则会发生死锁:
import threading resource.lock = threading.lock() resource = 0 resource.lock.acquire() resource.lock.acquire() resource += 1 resource.lock.release() resource.lock.release()
为解决同一线程中不能多次请求同一资源的问题,python提供了“可重入锁”:threading.RLock
,RLock
内部维护着一个Lock
和一个counter
变量,counter
记录了acquire
的次数,从而使得资源可以被多次acquire
。
直到一个线程所有的acquire
都被release
,其他的线程才能获得资源 。用法和threading.Lock
类相同,即比如递归锁的使用:
import threading lock = threading.RLock() def dosomething(lock): lock.acquire() # do something lock.release() lock.acquire() dosomething(lock) lock.release()
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
1.问题说明最近用DataFrame做大数据处理,发现处理速度特别慢,追究原因,发现是循环处理时,loc,iloc速度都特别慢,当数据量特别大得时候真的是超级慢。查很多资料,发现没有详细说明,以下为解决办法2.问题解决使用Pandas.Series.apply方法,可以对一列数据快速进行处理Series.apply(*func*,*convert_dtype=True*,*arg
这篇文章主要介绍了python使用openpyxl库读写Excel表格的方法(增删改查操作),本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
Python内置函数-memoryview() 函数。memoryview() 函数返回给定参数的内存查看对象(Momory view)。
这篇文章主要介绍了python3 最常用的三种装饰器语法总结,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
本文给大家分享Python 实时获取任务请求对应的Nginx日志的方法,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008