python 之 併發編程(守護線程與守護進程的區別、線程互斥鎖、死鎖現象與遞歸鎖、信號量、GIL全局解釋器鎖)

9.94 守護線程與守護進程的區別

1.對主進程來講,運行完畢指的是主進程代碼運行完畢
2.對主線程來講,運行完畢指的是主線程所在的進程內全部非守護線程通通運行完畢,主線程纔算運行完畢

詳細解釋:
1.主進程在其代碼結束後就已經算運行完畢了(守護進程在此時就被回收),而後主進程會一直等非守護的子進程都運行完畢後回收子進程的資源(不然會產生殭屍進程),纔會結束,
2.主線程在其餘非守護線程運行完畢後纔算運行完畢(守護線程在此時就被回收)。由於主線程的結束意味着進程的結束,進程總體的資源都將被回收,而進程必須保證非守護線程都運行完畢後才能結束。

9.95 線程互斥鎖

from threading import Thread,Lock import time mutex=Lock() x=100
def task(): global x mutex.acquire() temp=x time.sleep(0.1) x=temp-1 mutex.release() ​ if __name__ == '__main__': start=time.time() t_l=[] for i in range(100): t=Thread(target=task) t_l.append(t) t.start() for t in t_l: t.join() ​ print('',x)            #主 0
    print(time.time()-start)  #10.1311

9.96 死鎖現象與遞歸鎖

mutexA=mutexB=RLock() 一個線程拿到鎖,counter加1,該線程內又碰到加鎖的狀況,則counter繼續加1,這期間全部其餘線程都只能等待,等待該線程釋放全部鎖,即counter遞減到0爲止python

from threading import Thread,Lock,RLock import time # mutexA=Lock() # mutexB=Lock() #產生死鎖
mutexA=mutexB=RLock()    #遞歸鎖
class MyThread(Thread): def run(self): self.f1() self.f2() ​ def f1(self): mutexA.acquire() print('%s 拿到了A鎖' %self.name) mutexB.acquire() print('%s 拿到了B鎖' %self.name) mutexB.release() mutexA.release() ​ def f2(self): mutexB.acquire() print('%s 拿到了B鎖' %self.name) time.sleep(0.1) mutexA.acquire() print('%s 拿到了A鎖' %self.name) mutexA.release() mutexB.release() ​ if __name__ == '__main__': for i in range(10): t=MyThread() t.start() ​ print('')

9.97 信號量

同進程的同樣,Semaphore管理一個內置的計數器,每當調用acquire( )時內置計數器-1;調用release() 時內置計數器+1; 計數器不能小於0;當計數器爲0時,acquire()將阻塞線程直到其餘線程調用release()web

# from multiprocessing import Semaphore
from threading import Thread,Semaphore,current_thread import time,random ​ sm=Semaphore(5) def go_wc(): sm.acquire() print('%s 上廁所ing' %current_thread().getName()) time.sleep(random.randint(1,3)) sm.release() ​ if __name__ == '__main__': for i in range(23): t=Thread(target=go_wc) t.start()

與進程池是徹底不一樣的概念,進程池Pool(4),最大隻能產生4個進程,並且從頭至尾都只是這四個進程,不會產生新的,而信號量是產生一堆線程/進程安全

9.10 GIL解釋器鎖

GIL:全局解釋器鎖 GIL本質就是一把互斥鎖,是夾在解釋器身上的,每個python進程內都有這麼一把鎖,同一個進程內的全部線程都須要先搶到GIL鎖,才能執行解釋器代碼多線程

GIL會對單進程下的多個線程形成什麼樣的影響: 多線程要想執行,首先須要爭搶GIL,對全部待執行的線程來講,GIL就至關於執行權限,同一時刻只有一個線程爭搶成功,即單進程下的多個線程同一時刻只有一個在運行,意味着單進程下的多線程沒有並行的效果,可是有併發的效果併發

ps:分散於不一樣進程內的線程不會去爭搶同一把GIL,只有同一個進程的多個線程才爭搶同一把GILapp

爲何要有GIL: Cpython解釋器的內存管理機制不是線程安全的dom

GIL的優缺點: 優勢: 保證Cpython解釋器內存管理的線程安全socket

缺點: 同一進程內全部的線程同一時刻只能有一個執行,也就說Cpython解釋器的多線程沒法實現並行性能

GIL與自定義互斥鎖的異同,多個線程爭搶GIL與自定義互斥鎖的過程分析: 相同:都是互斥鎖 不一樣點:GIL是加到解釋器上的,做用於全局,自定義互斥鎖做用於局部;單進程內的全部線程都會去搶GIL,單進程內的只有一部分線程會去搶自定義的互斥鎖ui

9.101 Cpython解釋器併發效率驗證

單進程下的多個線程是沒法並行,沒法並行意味着不能利用多核優點

計算密集型應該使用多進程,如金融分析;IO密集型應該使用多線程,多核對性能的提高微不足道,如socket,爬蟲,web

9.102 線程互斥鎖與GIL對比

GIL保護的是解釋器級的數據,保護用戶本身的數據則須要本身加鎖處理

from threading import Thread,Lock import time mutex=Lock() count=0 def task(): global count mutex.acquire() #GIL只能讓線程先訪問到解釋器的代碼,即拿到執行權限,而後將target的代碼交給解釋器的代
    temp=count      #碼去執行,但線程拿不到mutex,一樣要等待
    time.sleep(0.1) count=temp+1 mutex.release() ​ if __name__ == '__main__': t_l=[] for i in range(2): t=Thread(target=task) t_l.append(t) t.start() for t in t_l: t.join() ​ print('',count)    #主 2
相關文章
相關標籤/搜索