python學習-----9.7-----GIL、死鎖遞歸鎖、信號量,event事件

GIL介紹python

  GIL本質就是一把互斥鎖,既然是互斥鎖,全部互斥鎖的本質都同樣,都是將併發運行變成串行,以此來控制同一時間內共享數據只能被一個任務所修改,進而保證數據安全。每一個進程內都會存在一把GIL,同一個進程內的多個線程必須搶到GIL以後才能使用Cpython解釋器來執行本身的代碼,即同一個進程下的多個線程沒法實現並行,可是能夠實現併發安全

  在Cpython解釋器下,若是想實現並行能夠開啓多個進程多線程

爲什麼要有GIL併發

  由於Cpython解釋器的垃圾回收機制不是線程安全的app

總結:dom

  io密集型:用多線程(開發中大部分用多線程)ide

  計算密集型:用多進程ui

 

GIL與自定義互斥鎖的區別spa

  前者是解釋器級別的(固然保護的就是解釋器級別的數據,好比垃圾回收的數據),後者是保護用戶本身開發的應用程序的數據,很明顯GIL不負責這件事,只能用戶自定義加鎖處理,即Lock線程

  鎖一般被用來實現對共享資源的同步訪問。爲每個共享資源建立一個Lock對象,當你須要訪問該資源時,調用acquire方法來獲取鎖對象(若是其它線程已經得到了該鎖,則當前線程需等待其被釋放),待資源訪問完後,再調用release方法釋放鎖:

from threading import Thread,Lock
import os,time
def work():
    global n
    lock.acquire()
    temp=n
    time.sleep(0.1)
    n=temp-1
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    n=100
    l=[]
    for i in range(100):
        p=Thread(target=work)
        l.append(p)
        p.start()
    for p in l:
        p.join()

    print(n) #結果確定爲0,由原來的併發執行變成串行,犧牲了執行效率保證了數據安全
View Code

 

 

死鎖與遞歸鎖

  死鎖現象:指的是互相拿了對方須要的鑰匙但都不放手,致使了程序的阻塞

  遞歸鎖:就是爲了解決死鎖現象: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

 

 

信號量

  semaphore 控制統一進程下的併發的線程個數

 

from threading import Thread,Semaphore
import time,random

sm=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

  

線程的一個關鍵特性是每一個線程都是獨立運行且狀態不可預測。若是程序中的其 他線程須要經過判斷某個線程的狀態來肯定本身下一步的操做,這時線程同步問題就會變得很是棘手。爲了解決這些問題,咱們須要使用threading庫中的Event對象。 對象包含一個可由線程設置的信號標誌,它容許線程等待某些事件的發生。在 初始狀況下,Event對象中的信號標誌被設置爲假。若是有線程等待一個Event對象, 而這個Event對象的標誌爲假,那麼這個線程將會被一直阻塞直至該標誌爲真。一個線程若是將一個Event對象的信號標誌設置爲真,它將喚醒全部等待這個Event對象的線程。若是一個線程等待一個已經被設置爲真的Event對象,那麼它將忽略這個事件, 繼續執行
爲什麼引用Event
from threading import Thread,Event
import time

event=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
相關文章
相關標籤/搜索