python之GIL全域性直譯器鎖,自定義互斥鎖,死鎖與遞迴鎖

Petrus_shuai發表於2018-09-07

一.關於GIL與自定義互斥鎖的區別

1.GIL是python直譯器自帶的鎖,自定義互斥鎖是我們程式裡面自定義的鎖

2.GIL鎖只保證關於垃圾回收那一部分的資料是安全的,但是程式裡面自定義的資料GIL無法保證,只能增加自定義鎖

程式碼如下:

1.有自定義互斥鎖的情況

from threading  import Thread,Lock
import time,random

n=100
mutex=Lock()

def task():
    global n
    with mutex:

        temp=n
        time.sleep(0.1)
        n=temp-1



if __name__ == '__main__':
    l=[]
    for i in range(100):
        t=Thread(target=task)
        l.append(t)
        t.start()
    for t in l:
        t.join()

    print(n) #0

2.只有GIL鎖,沒有自定義互斥鎖的情況

from threading  import Thread,Lock
import time,random

n=100
# mutex=Lock()

def task():
    global n
    # with mutex:

    temp=n
    time.sleep(0.1)
    n=temp-1



if __name__ == '__main__':
    l=[]
    for i in range(100):
        t=Thread(target=task)
        l.append(t)
        t.start()
    for t in l:
        t.join()

    print(n)  #99

二.死鎖與遞迴鎖

當自定義鎖運用的不得當,會造成死鎖,死鎖的解決方案是遞迴鎖   自定義鎖只能aquire一次  而遞迴鎖可以aquire多次

from threading import Thread,Lock,RLock
import time

mutexA=Lock()
mutexB=Lock()
#mutexB=mutexA=RLock()


class Mythead(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(2)
        mutexA.acquire()
        print('%s 搶到了A鎖' %self.name)
        mutexA.release()
        mutexB.release()

if __name__ == '__main__':
    for i in range(100):
        t=Mythead()
        t.start()

 列印結果:

遞迴鎖可以被一個執行緒aquire多次,每aquire一次計數加一,導致其它執行緒無法aquire這把鎖(只有計數為零才可以被aquire)

from threading import Thread,Lock,RLock
import time

# mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock()


class Mythead(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print('%s 搶到A鎖' %self.name)  ..1  ..2
        mutexB.acquire()
        print('%s 搶到B鎖' %self.name)  ..1
        mutexB.release()
        mutexA.release()

    def f2(self):
        mutexB.acquire() ..1
        print('%s 搶到了B鎖' %self.name) ..1
        time.sleep(2)
        mutexA.acquire()
        print('%s 搶到了A鎖' %self.name)
        mutexA.release()
        mutexB.release()

if __name__ == '__main__':
    for i in range(100):
        t=Mythead()
        t.start()

列印結果:

三.訊號量

訊號量本質也是一把鎖,但是與互斥鎖不一樣的是,訊號量是有多把鎖,能保證同一時刻多個執行緒同時執行

 

四.event事件

多個執行緒之間需要協同工作,一個執行緒的執行依賴另一個執行緒為它做好準備工作

from threading import Thread,Event
import time,random


event=Event()


def light():
    print("紅燈正亮")
    time.sleep(random.randint(1,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=("車輛%s" %i ,))
        t.start()

五.執行緒Queue

import queue


q=queue.Queue()  #先進先出
q.put(1)
q.put(2)
q.put(3)

print(q.get()) #1
print(q.get()) #2
print(q.get()) #3


q=queue.LifoQueue()  #後進先出
q.put(10)
q.put(20)
q.put(30)
print(q.get()) #30
print(q.get()) #20
print(q.get()) #10


q=queue.PriorityQueue()  #元組裡面第一個引數越小 優先順序越高
q.put((100,"a"))
q.put((0,"b"))
q.put((-1,"c"))
print(q.get()) #c
print(q.get()) #b
print(q.get()) #a

 

 

 

 

 

相關文章