Python多线程操作之互斥锁、递归锁、信号量、事件实例详解
本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。分享给大家供大家参考,具体如下:
互斥锁: 为什么要有互斥锁:由于多线程是并行的,如果某一线程取出了某一个数据将要进行操作,但它还没有那么快执行完操作,这时候如果另外一个线程也要操作这个数据,那么这个数据可能会因为两次操作而发生错误import time,threadingx=6def run1(): print('run1我拿到了数据:',x) print('我现在还不想操作,先睡一下') time.sleep(3) print('再看一下数据,稳一稳',x)def run2(): global x print('run2我拿到了数据:', x) x=5 print(x)t1=threading.Thread(target=run1)t2=threading.Thread(target=run2)t1.start()t2.start()t1.join()t2.join()
使用互斥锁来更改上段代码
import time,threadingx=6def run1(): lock.acquire() global x print('run1我拿到了数据,x=',x) print('我现在还不想操作,先睡一下') time.sleep(3) print('再看一下数据,稳一稳,x=',x) x+=1 print('run1操作完毕:x=',x) lock.release()def run2(): lock.acquire() global x print('run2我拿到了数据:', x) x+=1 print('run2操作完毕:x=',x) lock.release()lock=threading.Lock()#生成一个锁对象t1=threading.Thread(target=run1)t2=threading.Thread(target=run2)t1.start()t2.start()start_time=time.time()t1.join()t2.join()print('最终的x=',x)print(time.time()-start_time)#3.0多说明,由于受到锁的影响,run2要等待run1释放lock,所以变成了串行
这种互斥锁在操作系统中可以称作“临界区”,如果想了解更多:
https://baike.baidu.com/item/%E4%B8%B4%E7%95%8C%E5%8C%BA/8942134?fr=aladdin
【以过独木桥为例】:桥只能容一个人通过,A只能看得到北边桥上有没有人,看不到南边桥有没有人,当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人,B情况相反:【于是当两个人一起过桥的时候就会发生死锁】
import threading,time'''A只能看得到北边桥上有没有人,看不到南边桥有没有人,当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人'''def A(): lockNorth.acquire()#拿到北边桥的锁 print('A过桥北') time.sleep(3)#过桥中 lockSorth.acquire()#企图过到南边桥, print('A过桥南') time.sleep(3) # 过桥中 lockSorth.release() lockNorth.release() print('A过桥成功')'''B只能看得到南边桥上有没有人,看不到北边桥有没有人,当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人'''def B(): lockSorth.acquire() # 企图过到南边桥, print('B过桥南') time.sleep(3) # 过桥中 lockNorth.acquire() # 拿到北边桥的锁 print('B过桥北') time.sleep(3) # 过桥中 lockNorth.release() lockSorth.release() print('B过桥成功')lockNorth=threading.Lock()lockSorth=threading.Lock()tA=threading.Thread(target=A)tB=threading.Thread(target=B)tA.start()tB.start()tA.join()tB.join()
使用递归锁来解决上面的死锁问题:
import threading,time'''A只能看得到北边桥上有没有人,看不到南边桥有没有人,当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人'''def A(): lock.acquire()#拿到北边桥的锁 print('A过桥北') time.sleep(3)#过桥中 lock.acquire()#企图过到南边桥, print('A过桥南') time.sleep(3) # 过桥中 lock.release() lock.release() print('A过桥成功')'''B只能看得到南边桥上有没有人,看不到北边桥有没有人,当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人'''def B(): lock.acquire() # 拿南桥锁, print('B过桥南') time.sleep(3) # 过桥中 lock.acquire() # 企图拿北桥的锁 print('B过桥北') time.sleep(3) # 过桥中 lock.release() lock.release() print('B过桥成功')lock=threading.RLock()tA=threading.Thread(target=A)tB=threading.Thread(target=B)tA.start()tB.start()tA.join()tB.join()
【由于本质是一把锁,A拿到锁后,B要等待】
信号量: 什么是信号量:信号量可以限制进入的线程的数量。
如何使用信号量: 创建信号量对象:信号量对象=threading.BoundedSemaphore(x),x是限制进程的数量 当有进程需要进入的时候,调用acquire()来减少信号量:信号量对象.acquire() 当有进程离开的时候,调用release()来增加信号量:信号量对象.release()import threading,timedef run(): s.acquire() print('hello') time.sleep(1.5) s.release()s=threading.BoundedSemaphore(3)#限制3个threading_list=[]for i in range(12):#创建12个线程 obj=threading.Thread(target=run) obj.setDaemon(True) # 设置守护线程,避免干扰主线程运行,并行等待 obj.start()for i in range(4): print('')#为了把结果分割,可以清楚看出分为了三组 time.sleep(1.5)#结果分为三组是因为运行的太快了,三个线程装入的时间差太小
import threading,timedef read(): while True: if event.is_set(): print('事件已设置,我要读了!!!!') time.sleep(1) else:#事件未设置 print('还没写好,我要等咯') event.wait()#那么就等着咯 #如果等到了 print('终于等到了!那么我又可以读了') time.sleep(1)def write(): event.clear()#初始设空 while True: time.sleep(3)#写 event.set()#设置事件,一旦set,那么读者wait就有返回了,读者可以继续运行了 print('write:写好了') time.sleep(2)#等人读 event.clear()#清除事件event=threading.Event() #创建事件对象t1=threading.Thread(target=write)t2=threading.Thread(target=read)t1.start()t2.start()t1.join()t2.join()'''结果显示:读者确实一直在等待写者写好'''
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总》
希望本文所述对大家Python程序设计有所帮助。
相关文章:
