python全局解釋器GIL鎖機(jī)制詳解
一、GIL全局解釋器鎖
1、GIL鎖不是python的特點(diǎn)。而是cpython的特點(diǎn)。
2、在cpython解釋器中,GIL是一把互斥鎖,用來保證進(jìn)程中同一個(gè)時(shí)刻只有一個(gè)線程在執(zhí)行。
3、在沒有GIL鎖的情況下,有可能多線程在執(zhí)行一個(gè)代碼的同時(shí),垃圾回收機(jī)制對(duì)所執(zhí)行代碼的變量直接進(jìn)行回收,其他的線程再使用該變量時(shí)會(huì)導(dǎo)致運(yùn)行錯(cuò)誤。
二、為什么會(huì)有GIL鎖?
python使用引用計(jì)數(shù)為主,標(biāo)記清楚和隔代回收為輔來進(jìn)行內(nèi)存管理。所有python腳本中創(chuàng)建的對(duì)象,都會(huì)配備一個(gè)引用計(jì)數(shù),來記錄有多少個(gè)指針來指向它。當(dāng)對(duì)象的引用技術(shù)為0時(shí),會(huì)自動(dòng)釋放其所占用的內(nèi)存。
假設(shè)有2個(gè)python線程同時(shí)引用一個(gè)數(shù)據(jù)(a=100,引用計(jì)數(shù)為1),
2個(gè)線程都會(huì)去操作該數(shù)據(jù),由于多線程對(duì)同一個(gè)資源的競(jìng)爭(zhēng),實(shí)際上引用計(jì)數(shù)為3,
但是由于沒有GIL鎖,導(dǎo)致引用計(jì)數(shù)只增加1(引用計(jì)數(shù)為2)
這造成的后果是,當(dāng)?shù)?個(gè)線程結(jié)束時(shí),會(huì)把引用計(jì)數(shù)減少為1;當(dāng)?shù)?個(gè)線程結(jié)束時(shí),會(huì)把引用計(jì)數(shù)減少為0;
當(dāng)下一個(gè)線程再次視圖訪問這個(gè)數(shù)據(jù)時(shí),就無法找到有效的內(nèi)存了**

三、多線程無法利用多核優(yōu)勢(shì)?
由于GIL鎖的存在,即使是多個(gè)線程處理任務(wù),但是最終只有一個(gè)線程在工作,那么是不是多線程真的一點(diǎn)用處都沒有了呢?
對(duì)于需要執(zhí)行的任務(wù)來說,分為兩種:計(jì)算密集型、IO 密集型
假如一個(gè)計(jì)算密集型的任務(wù)需要10s的執(zhí)行時(shí)間,總共有4個(gè)這樣的任務(wù)
在 4核及以上的情況下:
多進(jìn)程:需要開啟 4 個(gè)進(jìn)程,但是 4 個(gè) CPU 并行,最終只需要消耗 10s 多一點(diǎn)的時(shí)間。
多線程:只需要開1 個(gè)進(jìn)程,這個(gè)進(jìn)程開啟 4 個(gè)線程,開啟線程所消耗的資源很少,但是由于最終執(zhí)行是只有一個(gè) CPU 可以工作,所以最終消耗 40s 多的時(shí)間。
假如是多個(gè) IO密集型 的任務(wù)
CPU 大多數(shù)時(shí)間是處于閑置狀態(tài),頻繁的切換
多進(jìn)程:進(jìn)程進(jìn)行切換需要消耗大量資源
多線程:線程進(jìn)行切換并不需要消耗大量資源
計(jì)算密集型和IO密集型
計(jì)算密集型:要進(jìn)行大量的數(shù)值計(jì)算,例如進(jìn)行上億的數(shù)字計(jì)算、計(jì)算圓周率、對(duì)視頻進(jìn)行高清解碼等等。這種計(jì)算密集型任務(wù)雖然也可以用多任務(wù)完成,但是花費(fèi)的主要時(shí)間在任務(wù)切換的時(shí)間,此時(shí)CPU執(zhí)行任務(wù)的效率比較低。
IO密集型:涉及到網(wǎng)絡(luò)請(qǐng)求(time.sleep())、磁盤IO的任務(wù)都是IO密集型任務(wù),這類任務(wù)的特點(diǎn)是CPU消耗很少,任務(wù)的大部分時(shí)間都在等待IO操作完成(因?yàn)镮O的速度遠(yuǎn)遠(yuǎn)低于CPU和內(nèi)存的速度)。對(duì)于IO密集型任務(wù),任務(wù)越多,CPU效率越高,但也有一個(gè)限度。
計(jì)算密集型——采用多進(jìn)程
執(zhí)行時(shí)間為: 4.062887668609619
from multiprocessing import Process
import time
def func1():
sum=0
for i in range(100000000):
sum+=1
print(sum)
if __name__ == '__main__':
now=time.time()
l=[]
for i in range(10):
p=Process(target=func1)
p.start()
l.append(p)
for p in l:
p.join()
end=time.time()
print('執(zhí)行時(shí)間為:',end-now)
計(jì)算密集型——采用多線程
執(zhí)行時(shí)間為: 27.6159188747406
from threading import Thread
import time
def func1():
sum=0
for i in range(100000000):
sum+=1
print(sum)
if __name__ == '__main__':
now=time.time()
l=[]
for i in range(10):
p=Thread(target=func1)
p.start()
l.append(p)
for p in l:
p.join()
end=time.time()
print('執(zhí)行時(shí)間為:',end-now)IO密集型——采用多進(jìn)程
執(zhí)行時(shí)間為: 5.388434886932373
from multiprocessing import Process
import time
def func1():
time.sleep(2)
if __name__ == '__main__':
now=time.time()
l=[]
for i in range(100):
p=Process(target=func1)
p.start()
l.append(p)
for p in l:
p.join()
end=time.time()
print('執(zhí)行時(shí)間為:',end-now)
IO密集型——采用多線程
執(zhí)行時(shí)間為: 2.0174973011016846
from threading import Thread
import time
def func1():
time.sleep(2)
if __name__ == '__main__':
now=time.time()
l=[]
for i in range(100):
p=Thread(target=func1)
p.start()
l.append(p)
for p in l:
p.join()
end=time.time()
print('執(zhí)行時(shí)間為:',end-now)
四、總結(jié)
對(duì)于IO密集型應(yīng)用,即便有GIL存在,由于IO操作會(huì)導(dǎo)致GIL釋放,其他線程能夠獲得執(zhí)行權(quán)限。由于多線程的通訊成本低于多進(jìn)程,因此偏向使用多線程。
對(duì)于計(jì)算密集型應(yīng)用,由于CPU一直處于被占用狀態(tài),GIL鎖直到規(guī)定時(shí)間才會(huì)釋放,然后才會(huì)切換狀態(tài),導(dǎo)致多線程處于絕對(duì)的劣勢(shì),此時(shí)可以采用多進(jìn)程+協(xié)程。
到此這篇關(guān)于python全局解釋器GIL鎖機(jī)制的文章就介紹到這了,更多相關(guān)python GIL鎖詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python突破多線程限制GIL問題的4種實(shí)戰(zhàn)解法
- Python GIL(全局解釋器鎖)的使用小結(jié)
- Python多進(jìn)程開發(fā)之如何輕松突破GIL瓶頸
- Python學(xué)習(xí)之線程池與GIL全局鎖詳解
- Python中GIL的使用詳解
- 詳解Python中的GIL(全局解釋器鎖)詳解及解決GIL的幾種方案
- 淺談Python中的全局鎖(GIL)問題
- python 深入了解GIL鎖詳細(xì)
- 一篇文章快速了解Python的GIL
- 深入理解python虛擬機(jī)GIL詳解
- Python Threading 線程/互斥鎖/死鎖/GIL鎖
- Python全局解釋器鎖(GIL):提高多線程性能的最佳實(shí)踐
相關(guān)文章
Python中不同數(shù)據(jù)對(duì)象的空值校驗(yàn)的方法小結(jié)
Python中有多種數(shù)據(jù)對(duì)象,每種都有其特定的空值表示方法和校驗(yàn)方式,本文將深入探討這些空值校驗(yàn)的方法,有需要的小伙伴可以參考一下2024-04-04
利用Python實(shí)現(xiàn)Shp格式向GeoJSON的轉(zhuǎn)換方法
JSON(JavaScript Object Nonation)是利用鍵值對(duì)+嵌套來表示數(shù)據(jù)的一種格式,以其輕量、易解析的優(yōu)點(diǎn),這篇文章主要介紹了利用Python實(shí)現(xiàn)Shp格式向GeoJSON的轉(zhuǎn)換,需要的朋友可以參考下2019-07-07
Python+matplotlib實(shí)現(xiàn)折線圖的美化
這篇文章主要和大家分享一個(gè)非常有趣的Python教程—如何美化一個(gè)?matplotlib折線圖。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05
pygame用blit()實(shí)現(xiàn)動(dòng)畫效果的示例代碼
這篇文章主要介紹了pygame用blit()實(shí)現(xiàn)動(dòng)畫效果的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
Python flask框架實(shí)現(xiàn)查詢數(shù)據(jù)庫并顯示數(shù)據(jù)
這篇文章主要介紹了Python flask框架實(shí)現(xiàn)查詢數(shù)據(jù)庫并顯示數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Python如何操作office實(shí)現(xiàn)自動(dòng)化及win32com.client的運(yùn)用
這篇文章主要介紹了Python如何操作office實(shí)現(xiàn)自動(dòng)化及win32com.client的運(yùn)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
python數(shù)組排序方法之sort、sorted和argsort詳解
這篇文章主要給大家介紹了關(guān)于python數(shù)組排序方法之sort、sorted和argsort的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03
DJango的創(chuàng)建和使用詳解(默認(rèn)數(shù)據(jù)庫sqlite3)
今天小編就為大家分享一篇DJango的創(chuàng)建和使用詳解(默認(rèn)數(shù)據(jù)庫sqlite3),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11

