1. 程式人生 > >並發編程——全局解釋器鎖GIL

並發編程——全局解釋器鎖GIL

rand 安全 能夠 互斥 star list lis 解釋器 semaphore

1.全局解釋器鎖GIL

  • GIL其實就是一把互斥鎖(犧牲了效率但是保證了數據的安全)。

  • 線程是執行單位,但是不能直接運行,需要先拿到python解釋器解釋之後才能被cpu執行

  • 同一時刻同一個進程內多個線程無法實現並行,但是可以實現並發

  • 為什麽要有GIL是因為它內部的垃圾回收機制不是線程安全的

  • 垃圾回收機制也是一個任務,跟你的代碼不是串行運行,如果是串行會明顯有卡頓

  • 這個垃圾回收到底是開進程還是開線程?肯定是線程,線程肯定也是一段代碼,所以想運行也必須要拿到python解釋器

  • 假設能夠並行,會出現什麽情況?一個線程剛好要造一個a=1的綁定關系之前,這個垃圾線程來掃描,矛盾點就來了,誰成功都不對!

  • 也就意味著在Cpython解釋器上有一把GIL全局解釋器鎖

  • 同一個進程下的多個線程不能實現並行但是能夠實現並發,多個進程下的線程能夠實現並行

1.python中的多線程到底有沒有用?

單核情況下:四個任務

多核情況下:四個任務

計算密集型:一個任務算十秒,四個進程和四個線程,肯定是進程快

IO密集型:任務都是純io情況下,線程開銷比進程小,肯定是線程好

技術分享圖片
```python
# 計算密集型
from multiprocessing import Process
from threading import Thread
import os,time
def work(): res=0 for i in range(100000000): res*=i if __name__ == __main__: l=[] print(os.cpu_count()) # 本機為12核 start=time.time() for i in range(12): # p=Process(target=work) #耗時8s多 p=Thread(target=work) #耗時44s多 l.append(p) p.start()
for p in l: p.join() stop=time.time() print(run time is %s %(stop-start)) # IO密集型 from multiprocessing import Process from threading import Thread import threading import os,time def work(): time.sleep(2) if __name__ == __main__: l=[] print(os.cpu_count()) #本機為12核 start=time.time() for i in range(400): p=Process(target=work) #耗時12s多,大部分時間耗費在創建進程上 # p=Thread(target=work) #耗時2s多 l.append(p) p.start() for p in l: p.join() stop=time.time() print(run time is %s %(stop-start))
View Code

2.GIL與自定義互斥鎖

技術分享圖片
不同的數據需要加不同的鎖才能保證數據的安全,GIL鎖只是對線程加鎖,對數據並沒有加鎖的效果

```python
from threading import Thread,Lock
import time

mutex=Lock()
n=100
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)
# 對於修改不同的數據,需要加不同的鎖進行處理
View Code

3.死鎖與遞歸鎖(了解)

自定義鎖一次acquire必須對應一次release,不能連續acquire

遞歸鎖可以連續的acquire,每acquire一次計數加一

技術分享圖片
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()
View Code

4.信號量(了解)

自定義的互斥鎖如果是一個廁所,那麽信號量就相當於公共廁所,門口掛著多個廁所的鑰匙。搶和釋放跟互斥鎖一致

技術分享圖片
from threading import Thread,Semaphore
import time
import random
sm = Semaphore(5)  # 公共廁所裏面有五個坑位,在廁所外面放了五把鑰匙

def task(name):
    sm.acquire()
    print(%s正在蹲坑%name)
    # 模擬蹲坑耗時
    time.sleep(random.randint(1,5))
    sm.release()


if __name__ == __main__:
    for i in range(20):
        t = Thread(target=task,args=(傘兵%s號%i,))
        t.start()
View Code

5.Event事件

一些線程需要等待另外一些線程運行完畢才能運行,類似於發射信號一樣

技術分享圖片
from threading import Thread,Event
import time
event = Event()  # 造了一個紅綠燈


def light():
    print(紅燈亮著的)
    time.sleep(3)
    print(綠燈亮了)
    event.set()


def car(name):
    print(%s 車正在等紅燈%name)
    event.wait()
    print(%s 車加油門飆車走了%name)


if __name__ == __main__:
    t = Thread(target=light)
    t.start()

    for i in range(10):
        t = Thread(target=car,args=(%s%i,))
        t.start()
View Code

6.線程queue

同一個進程下的線程數據都是共享的為什麽還要用queue?queue本身自帶鎖的功能,能夠保證數據的安全

技術分享圖片
# 我們現在的q只能在本地使用,後面我們會學基於網絡的q 
import queue

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

queue.LifoQueue() #後進先出->堆棧
q=queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())

queue.PriorityQueue() #優先級
q=queue.PriorityQueue(3) #優先級,優先級用數字表示,數字越小優先級越高
q.put((10,a))
q.put((-1,b))
q.put((100,c))
print(q.get())
print(q.get())
print(q.get())
View Code

並發編程——全局解釋器鎖GIL