dis库是python(默认的cpython)自带的一个库,可以用来分析字节码
import disdef add1(): a += 1def desc1(): b -= 1 print(b)print(dis.dis(add1))print(dis.dis(desc1))
执行结果:
前面的数字 17、21、22 第一列表示对应源代码的行数。第二列的数字是字节码的索引。第三列是指令本身对应的人类可读的名字。第四列表示指令的参数。第5列则是计算后的实际参数。
17 0 LOAD_FAST 0 (a) #加载变量a到内存 2 LOAD_CONST 1 (1) #加载1 到内存 4 INPLACE_ADD #执行加 计算 6 STORE_FAST 0 (a) #把结果赋值给a 8 LOAD_CONST 0 (None) 10 RETURN_VALUENone 21 0 LOAD_FAST 0 (b) 2 LOAD_CONST 1 (1) 4 INPLACE_SUBTRACT 6 STORE_FAST 0 (b) 22 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 0 (b) 12 CALL_FUNCTION 1 14 POP_top 16 LOAD_CONST 0 (None) 18 RETURN_VALUENone
假如add1和desc1函数里的 变量 a和b使用同一个全局变量,并分别放到多线程中运行,:
import disfrom threading import Threadfrom threading import Locka = 0lock = Lock()def add1(): global a global lock for x in range(1000000): # lock.acquire() a += 1 # lock.release()def desc1(): global a global lock for x in range(1000000): # lock.acquire() a -= 1 # lock.release()if __name__ == "__main__": thread1 = Thread(target=add1) thread2 = Thread(target=desc1) thread1.start() thread2.start() thread1.join() thread2.join() print(a)
执行结果会变,因为Thread的run方法不是线程安全的,GIL 在线程运行过程中,会不断切换,又共用的同个变量就出现这问题了。
(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py -124668(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py 694972(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py -246256(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py -310544(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py -592669(zabbixweb) D:\data\python\zabbixAPIweb\project\project>
为了解决这个问题,Python 的 threading 模块引入了锁(Lock)。threading 模块提供了 Lock 和 RLock 两个类,它们都提供了如下两个方法来加锁和释放锁:
acquire(blocking=True, timeout=-1):请求对 Lock 或 RLock 加锁,其中 timeout 参数指定加锁多少秒。release():释放锁。
Lock 和 RLock 的区别如下:
由此可见,RLock 锁具有可重入性。也就是说,同一个线程可以对已被加锁的 RLock 锁再次加锁,RLock 对象会维持一个计数器来追踪 acquire() 方法的嵌套调用,线程在每次调用 acquire() 加锁后,都必须显式调用 release() 方法来释放锁。所以,一段被锁保护的方法可以调用另一个被相同锁保护的方法。
Lock 是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程在开始访问共享资源之前应先请求获得 Lock 对象。当对共享资源访问完成后,程序释放对 Lock 对象的锁定。
import disfrom threading import Threadfrom threading import Locka = 0lock = Lock()def add1(): global a global lock for x in range(1000000): lock.acquire() a += 1 lock.release()def desc1(): global a global lock for x in range(1000000): lock.acquire() a -= 1 lock.release()if __name__ == "__main__": thread1 = Thread(target=add1) thread2 = Thread(target=desc1) thread1.start() thread2.start() thread1.join() thread2.join() print(a)
(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py 0(zabbixweb) D:\data\python\zabbixAPIweb\project\project>d:/data/python/environment/zabbixweb/Scripts/python.exe d:/data/python/zabbixAPIweb/project/project/test16.py 0
总结
以上是内存溢出为你收集整理的python-线程同步 - Lock、RLock学习全部内容,希望文章能够帮你解决python-线程同步 - Lock、RLock学习所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)