python学习-----9.7-----GIL、死锁递归锁、信号量,event事件
GIL介紹
GIL本質(zhì)就是一把互斥鎖,既然是互斥鎖,所有互斥鎖的本質(zhì)都一樣,都是將并發(fā)運(yùn)行變成串行,以此來控制同一時(shí)間內(nèi)共享數(shù)據(jù)只能被一個(gè)任務(wù)所修改,進(jìn)而保證數(shù)據(jù)安全。每個(gè)進(jìn)程內(nèi)都會(huì)存在一把GIL,同一個(gè)進(jìn)程內(nèi)的多個(gè)線程必須搶到GIL之后才能使用Cpython解釋器來執(zhí)行自己的代碼,即同一個(gè)進(jìn)程下的多個(gè)線程無法實(shí)現(xiàn)并行,但是可以實(shí)現(xiàn)并發(fā)
在Cpython解釋器下,如果想實(shí)現(xiàn)并行可以開啟多個(gè)進(jìn)程
為何要有GIL
因?yàn)镃python解釋器的垃圾回收機(jī)制不是線程安全的
總結(jié):
io密集型:用多線程(開發(fā)中大部分用多線程)
計(jì)算密集型:用多進(jìn)程
?
GIL與自定義互斥鎖的區(qū)別
前者是解釋器級(jí)別的(當(dāng)然保護(hù)的就是解釋器級(jí)別的數(shù)據(jù),比如垃圾回收的數(shù)據(jù)),后者是保護(hù)用戶自己開發(fā)的應(yīng)用程序的數(shù)據(jù),很明顯GIL不負(fù)責(zé)這件事,只能用戶自定義加鎖處理,即Lock
鎖通常被用來實(shí)現(xiàn)對(duì)共享資源的同步訪問。為每一個(gè)共享資源創(chuàng)建一個(gè)Lock對(duì)象,當(dāng)你需要訪問該資源時(shí),調(diào)用acquire方法來獲取鎖對(duì)象(如果其它線程已經(jīng)獲得了該鎖,則當(dāng)前線程需等待其被釋放),待資源訪問完后,再調(diào)用release方法釋放鎖:
from threading import Thread,Lock import os,time def work():global nlock.acquire()temp=ntime.sleep(0.1)n=temp-1lock.release() if __name__ == '__main__':lock=Lock()n=100l=[]for i in range(100):p=Thread(target=work)l.append(p)p.start()for p in l:p.join()print(n) #結(jié)果肯定為0,由原來的并發(fā)執(zhí)行變成串行,犧牲了執(zhí)行效率保證了數(shù)據(jù)安全 View Code?
?
死鎖與遞歸鎖
死鎖現(xiàn)象:指的是互相拿了對(duì)方需要的鑰匙但都不放手,導(dǎo)致了程序的阻塞
遞歸鎖:就是為了解決死鎖現(xiàn)象:RLOOK
from threading import Thread,Lock import time mutexA=Lock() mutexB=Lock()class MyThread(Thread):def run(self):self.func1()self.func2()def func1(self):mutexA.acquire()print('\033[41m%s 拿到A鎖\033[0m' %self.name)mutexB.acquire()print('\033[42m%s 拿到B鎖\033[0m' %self.name)mutexB.release()mutexA.release()def func2(self):mutexB.acquire()print('\033[43m%s 拿到B鎖\033[0m' %self.name)time.sleep(2)mutexA.acquire()print('\033[44m%s 拿到A鎖\033[0m' %self.name)mutexA.release()mutexB.release()if __name__ == '__main__':for i in range(10):t=MyThread()t.start()''' Thread-1 拿到A鎖 Thread-1 拿到B鎖 Thread-1 拿到B鎖 Thread-2 拿到A鎖 然后就卡住,死鎖了 ''' View Code
?
?
信號(hào)量
semaphore 控制統(tǒng)一進(jìn)程下的并發(fā)的線程個(gè)數(shù)
?
from threading import Thread,Semaphore import time,randomsm=Semaphore(5)def task(name):sm.acquire()print('%s正在上廁所'%name)time.sleep(random.randint(1,3))sm.release()if __name__ == '__main__':for i in range(20):t=Thread(target=task,args=('路人%s'%i,))t.start() View Code?
Event
線程的一個(gè)關(guān)鍵特性是每個(gè)線程都是獨(dú)立運(yùn)行且狀態(tài)不可預(yù)測(cè)。如果程序中的其 他線程需要通過判斷某個(gè)線程的狀態(tài)來確定自己下一步的操作,這時(shí)線程同步問題就會(huì)變得非常棘手。為了解決這些問題,我們需要使用threading庫中的Event對(duì)象。 對(duì)象包含一個(gè)可由線程設(shè)置的信號(hào)標(biāo)志,它允許線程等待某些事件的發(fā)生。在 初始情況下,Event對(duì)象中的信號(hào)標(biāo)志被設(shè)置為假。如果有線程等待一個(gè)Event對(duì)象, 而這個(gè)Event對(duì)象的標(biāo)志為假,那么這個(gè)線程將會(huì)被一直阻塞直至該標(biāo)志為真。一個(gè)線程如果將一個(gè)Event對(duì)象的信號(hào)標(biāo)志設(shè)置為真,它將喚醒所有等待這個(gè)Event對(duì)象的線程。如果一個(gè)線程等待一個(gè)已經(jīng)被設(shè)置為真的Event對(duì)象,那么它將忽略這個(gè)事件, 繼續(xù)執(zhí)行 為何引用Event from threading import Thread,Event import timeevent=Event()def light():print('紅燈正亮著')time.sleep(3)event.set()#綠燈亮def car(name):print('車%s正在等綠燈'%name)event.wait()#等燈綠print('車%s通行'%name)if __name__ == '__main__':#紅綠燈t1=Thread(target=light)t1.start()#車for i in range(10):t=Thread(target=car,args=(i,))t.start() View Code
?
轉(zhuǎn)載于:https://www.cnblogs.com/Liu-guang-hui/p/9607129.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的python学习-----9.7-----GIL、死锁递归锁、信号量,event事件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WINDOWS下安装MYSQL—图文详解
- 下一篇: 下拉框处理(select)