GIL全域性直譯器鎖與IO模型
阿新 • • 發佈:2022-01-17
內容概要
GIL全域性直譯器鎖(重要理論)
驗證GIL的存在及功能
驗證python多執行緒是否有用
死鎖現象
程序池與執行緒池(使用頻率較高)
IO模型(理論部分)
可參考:
https://www.bilibili.com/video/BV1QE41147hU?p=500
內容詳細
GIL全域性直譯器鎖
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.) """ 1.python直譯器其實有很多版本(預設肯定使用的是CPython) 直譯器種類:Cpython、Jpython、pypython 在Cpython中GIL全域性直譯器鎖其實也是一把互斥鎖,主要用於阻止同一個程序下的多個執行緒同時被執行(python的多執行緒無法使用多核優勢) GIL肯定存在於Cpython直譯器中 主要原因就在於Cpython直譯器的記憶體管理不是執行緒安全的 2.內容管理>>>垃圾回收機制 引用計數 標記清除 分代回收 """ 1.GIL是Cpython直譯器的特點 2.python同一個程序內的多個執行緒無法利用多核優勢(不能並行但是可以併發) 3.同一程序內的多個執行緒要想執行必須先搶GIL鎖 4.所有的解釋型語言幾乎都無法實現同一個程序下的多個執行緒同時被執行
驗證GIL的存在
from threading import Thread import time m = 100 def test(): global m tmp = m # time.sleep(1) # 99 tmp -= 1 m = tmp for i in range(100): t = Thread(target=test) t.start() time.sleep(3) print(m) # 0 """ 同一程序下的多個執行緒雖然有GIL的存在不會出現並行的效果 但是如果執行緒內有IO操作還是會造成資料的錯亂 這個時候需要我們額外的新增互斥鎖 """
死鎖現象
from threading import Thread, Lock import time A = Lock() B = Lock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): A.acquire() print('%s 搶到了A鎖' % self.name) B.acquire() print('%s 搶到了B鎖' % self.name) time.sleep(1) B.release() print('%s 釋放了B鎖' % self.name) A.release() print('%s 釋放了A鎖' % self.name) def func2(self): B.acquire() print('%s 搶到了B鎖' % self.name) A.acquire() print('%s 搶到了A鎖' % self.name) time.sleep(1) A.release() print('%s 釋放了A鎖' % self.name) B.release() print('%s 釋放了B鎖' % self.name) for i in range(10): obj = MyThread() obj.start() """ 就算知道鎖的特性及使用方法 也不要輕易的使用 因為容易出現鎖死的現象 """
python多執行緒是否沒用
# 是否有用需要看情況而定(程式的型別)
# IO密集型
eg:四個任務 每個任務耗時10s
開設多程序沒有太大的優勢 10s+
遇到IO就需要切換 並且開設程序還需要申請記憶體空間和拷貝程式碼
開設多執行緒有優勢
不需要消耗額外的資源 10s+
# 計算密集型
eg:四個任務 每個任務耗時10s
開設多執行緒可以利用多核優勢 10s+
開設多執行緒無法利用多核優勢 40s+
"""
多程序結合多執行緒
"""
"""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()) # 獲取本機CPU核數 8核
start = time.time()
for i in range(400):
# p = Process(target=work) # 耗時22.46s多 大部分時間耗費在建立程序上
p = Thread(target=work) # 耗時2.07s多
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('run time is %s'%(stop-start))
"""計算密集型"""
from multiprocessing import Process
from threading import Thread
import os, time
def work():
res = 0
for i in range(100000000):
res *= 1
if __name__ == '__main__':
l = []
print(os.cpu_count()) # 本機為6核
start = time.time()
for i in range(8):
# p = Process(target=work) # 耗時17.13s多
p = Thread(target=work) # 耗時47.74s多
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('run time is %s' % (stop - start))
程序池與執行緒池
思考:能否無限制的開設程序或執行緒???
肯定是不能無限制開設的
如果單從技術層面上來說無限開設肯定是可以的並且是最高效的
但是從硬體層面上來說是無法實現的(硬體的發展永遠趕不上軟體的發展速度)
池
在保證計算機硬體不崩潰的前提下開設多程序和多執行緒
降低了程式的執行效率但是保證了計算機硬體的安全
程序池與執行緒池
程序池:提前開設了固定個數的程序 之後反覆呼叫這些程序完成工作(後續不在開設新的)
執行緒池:提前開設了固定個數的執行緒 之後反覆呼叫這些執行緒完成工作(後續不在開設新的)