Python锁机制如何理解,RLock()与Lock()有何不同
Admin 2022-08-03 群英技术资讯 669 次浏览
要回答这个问题,我们需要知道为什么需要使用锁机制。前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享资源时,如果此时没有预设对应的同步机制,就可能带来同一时刻多个线程同时访问同一个共享资源,即出现竞态,多数情况下我们是不希望出现这样的情况的,那么怎么避免呢?
先看一段代码:
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进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
有时候我们的证件照需要换底色,又来不及去照相馆拍照,用ps也不好抠图,所以今天给你们分享一下如何用python来抠图,并换底色
Python内置函数-classmethod()。classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
程序可以通过创建一个新的异常类来命名它们自己的异常。异常应该是典型的继承自Exception类,直接或间接的方式。异常python有一个大基类,继承了Exception。因此,我们的定制类也必须继承Exception。
怎样用python实现图片搜索图片功能?一些朋友比较好奇图搜图功能是怎样实现,因此这篇文章就主要给大家分享用python实现图片搜索图片功能,感兴趣的朋友可以参考。
Python矩阵输入python输入(数组、矩阵)一维输入对应不同变量一维数组的输入问题二维数组的输入问题Python矩阵输入经常在尝试python一些函数功能时想随便输入一个矩阵感
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008