最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python 深入了解GIL鎖詳細(xì)

 更新時(shí)間:2021年10月26日 11:01:17   作者:Silent丿丶黑羽  
這篇文章主要介紹了python 深入了解GIL鎖,python的使用者都知道Cpython解釋器有一個(gè)弊端,真正執(zhí)行時(shí)同一時(shí)間只會有一個(gè)線程執(zhí)行,這是由于設(shè)計(jì)者當(dāng)初設(shè)計(jì)的一個(gè)缺陷,里面有個(gè)叫GIL鎖的,但他到底是什么,接下來和小編一起進(jìn)入下面文章詳細(xì)內(nèi)容吧

前言:

python的使用者都知道Cpython解釋器有一個(gè)弊端,真正執(zhí)行時(shí)同一時(shí)間只會有一個(gè)線程執(zhí)行,這是由于設(shè)計(jì)者當(dāng)初設(shè)計(jì)的一個(gè)缺陷,里面有個(gè)叫GIL鎖的,但他到底是什么?我們只知道因?yàn)樗麑?dǎo)致python使用多線程執(zhí)行時(shí),其實(shí)一直是單線程,但是原理卻不知道,那么接下來我們就認(rèn)識一下GIL鎖

1、什么是GIL鎖

GIL(Global Interpreter Lock)不是Python獨(dú)有的特性,它只是在實(shí)現(xiàn)CPython(Python解釋器)時(shí),引入的一個(gè)概念。

在官方網(wǎng)站中定義如下:

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.)

由定義可知,GIL是一個(gè)互斥鎖(mutex)。它阻止了多個(gè)線程同時(shí)執(zhí)行Python字節(jié)碼,毫無疑問,這降低了執(zhí)行效率。理解GIL的必要性,需要了解CPython對于線程安全的內(nèi)存管理機(jī)制。

2、CPython對線程安全的內(nèi)存管理機(jī)制

Python使用引用計(jì)數(shù)來進(jìn)行內(nèi)存管理,在Python中創(chuàng)建的對象都會有引用計(jì)數(shù),來記錄有多少個(gè)指針指向它。當(dāng)引用計(jì)數(shù)的值為0時(shí),就會自動(dòng)釋放內(nèi)存

我們來看一個(gè)小例子,來解釋引用計(jì)數(shù)的原理:

>>> import sys
>>> a = []
>>> b = a
>>> sys.getrefcount(a)
3


可以看到,a 的引用計(jì)數(shù)值為 3,因?yàn)橛?a、b 和作為參數(shù)傳遞的 getrefcount 都引用了一個(gè)空列表。
如果有2個(gè)python線程同時(shí)引用a,那么2個(gè)線程都會嘗試對其進(jìn)行數(shù)據(jù)操作,多個(gè)線程同時(shí)對一個(gè)數(shù)據(jù)進(jìn)行增加或減少的操作,如果發(fā)生這種情況,則可能導(dǎo)致內(nèi)存泄漏

3、GIL鎖的產(chǎn)生

由于多個(gè)線程同時(shí)對數(shù)據(jù)進(jìn)行操作,會引發(fā)數(shù)據(jù)不一致,導(dǎo)致內(nèi)存泄漏,我們可以對其進(jìn)行加鎖,所以Cpython就創(chuàng)建了GIL

但是既然有了鎖,一個(gè)對象就需要一把鎖,那么多個(gè)對象就會有多把鎖,可能會給我們帶來2個(gè)問題

  • 1.死鎖(線程之間互相爭搶鎖的資源)
  • 2.反復(fù)獲取和釋放鎖而導(dǎo)致性能降低。

為了保證單線程情況下python的正常執(zhí)行和效率,GIL鎖(單一鎖)由此產(chǎn)生了,它添加了一個(gè)規(guī)則,即任何Python字節(jié)碼的執(zhí)行都需要獲取解釋器鎖。這樣可以防止死鎖(因?yàn)橹挥幸粋€(gè)鎖),并且不會帶來太多的性能開銷。但這實(shí)際上使所有受CPU約束的Python程序(指的是CPU密集型程序)都是單線程的。

4、GIL鎖的底層原理

上面這張圖,就是 GIL Python 程序的工作示例。其中,Thread 1、2、3 輪流執(zhí)行,每一個(gè)線程在開始執(zhí)行時(shí),都會鎖住 GIL,以阻止別的線程執(zhí)行;同樣的,每一個(gè)線程執(zhí)行完一段后,會釋放 GIL,以允許別的線程開始利用資源。

線程釋放GIL鎖有兩種情況:

  • 一是遇到IO操作,
  • 二是Time Tick到期。IO操作很好理解

比如發(fā)出一個(gè)http請求,等待響應(yīng)。那么Time Tick到期是什么呢?Time Tick規(guī)定了線程的最長執(zhí)行時(shí)間,超過時(shí)間后自動(dòng)釋放GIL鎖。Python 3 以后,間隔時(shí)間大致為15毫秒
 

雖然都是釋放GIL鎖,但這兩種情況是不一樣的。比如,Thread1遇到IO操作釋放GIL,由Thread2和Thread3來競爭這個(gè)GIL鎖,Thread1不再參與這次競爭。如果是Thread1因?yàn)門ime Tick到期釋放GIL(多數(shù)是CPU密集型任務(wù)),那么三個(gè)線程可以同時(shí)競爭這把GIL鎖,可能出現(xiàn)Thread1在競爭中勝出,再次執(zhí)行的情況。單核CPU下,這種情況不算特別糟糕。因?yàn)橹挥?個(gè)CPU,所以CPU的利用率是很高的。

在多核CPU下,由于GIL鎖的全局特性,無法發(fā)揮多核的特性,GIL鎖會使得多線程任務(wù)的效率大大降低。

Thread1在CPU1上運(yùn)行,Thread2在CPU2上運(yùn)行。GIL是全局的,CPU2上的Thread2需要等待CPU1上的Thread1讓出GIL鎖,才有可能執(zhí)行。如果在多次競爭中,Thread1都勝出,Thread2沒有得到GIL鎖,意味著CPU2一直是閑置的,無法發(fā)揮多核的優(yōu)勢。

為了避免同一線程霸占CPU,在python3.2版本之后,線程會自動(dòng)的調(diào)整自己的優(yōu)先級,使得多線程任務(wù)執(zhí)行效率更高。
既然GIL降低了多核的效率,那保留它的目的是什么呢?這就和線程執(zhí)行的安全有關(guān)。

5、Python GIL不能絕對保證線程安全

def add():
    global n
    for i in range(10**1000):
        n = n +1
def sub():
    global n
    for i in range(10**1000):
        n = n - 1
n = 0
import threading
a = threading.Thread(target=add,)
b = threading.Thread(target=sub,)
a.start()
b.start()
a.join()
b.join()
print n

上面的程序?qū)做了同樣數(shù)量的加法和減法,那么n理論上是0。但運(yùn)行程序,打印n,發(fā)現(xiàn)它不是0。問題出在哪里呢,問題在于python的每行代碼不是原子化的操作。比如n = n+1這步,不是一次性執(zhí)行的。如果去查看python編譯后的字節(jié)碼執(zhí)行過程,可以看到如下結(jié)果。

19 LOAD_GLOBAL              1 (n)
22 LOAD_CONST               3 (1)
25 BINARY_ADD          
26 STORE_GLOBAL             1 (n)


從過程可以看出,n = n +1操作分成了四步完成。因此,n = n+1不是一個(gè)原子化操作。

  • 1.加載全局變量n
  • 2.加載常數(shù)1
  • 3.進(jìn)行二進(jìn)制加法運(yùn)算
  • 4.將運(yùn)算結(jié)果存入變量n。

根據(jù)前面的線程釋放GIL鎖原則,線程a執(zhí)行這四步的過程中,有可能會讓出GIL。如果這樣,n=n+1的運(yùn)算過程就被打亂了。最后的結(jié)果中,得到一個(gè)非零的n也就不足為奇。

6、總結(jié)

對于IO密集型應(yīng)用,多線程的應(yīng)用和多進(jìn)程應(yīng)用區(qū)別不大。即便有GIL存在,由于IO操作會導(dǎo)致GIL釋放,其他線程能夠獲得執(zhí)行權(quán)限。由于多線程的通訊成本低于多進(jìn)程,因此偏向使用多線程。

對于計(jì)算密集型應(yīng)用,由于CPU一直處于被占用狀態(tài),GIL鎖直到規(guī)定時(shí)間才會釋放,然后才會切換狀態(tài),導(dǎo)致多線程處于絕對的劣勢,此時(shí)可以采用多進(jìn)程+協(xié)程。

到此這篇關(guān)于python 深入了解GIL鎖詳細(xì)的文章就介紹到這了,更多相關(guān)python 深入了解GIL鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

參考資料:

https://realpython.com/python-gil/
https://zhuanlan.zhihu.com/p/97218985

相關(guān)文章

  • 超詳細(xì)的Python安裝第三方庫常用方法匯總

    超詳細(xì)的Python安裝第三方庫常用方法匯總

    電腦網(wǎng)絡(luò)有點(diǎn)問題,直接安裝第三方庫的時(shí)候出現(xiàn)了各種問題,所以在這篇文章里記錄一下各種安裝第三方庫的方法吧,下面這篇文章主要給大家介紹了關(guān)于Python安裝第三方庫常用方法的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Python 如何將MP4文件轉(zhuǎn)為GIF圖片

    Python 如何將MP4文件轉(zhuǎn)為GIF圖片

    這篇文章主要介紹了Python 如何將MP4文件轉(zhuǎn)為GIF圖片,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-05-05
  • 執(zhí)行Python程序時(shí)模塊報(bào)錯(cuò)問題

    執(zhí)行Python程序時(shí)模塊報(bào)錯(cuò)問題

    這篇文章主要介紹了執(zhí)行Python程序時(shí)模塊報(bào)錯(cuò)問題及解決方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Python將字符串轉(zhuǎn)換為datetime對象的五種方法

    Python將字符串轉(zhuǎn)換為datetime對象的五種方法

    在Python編程中,我們經(jīng)常會遇到需要將字符串形式的日期和時(shí)間轉(zhuǎn)換為datetime對象的情況,例如,從文件、數(shù)據(jù)庫或網(wǎng)絡(luò)接口中獲取的數(shù)據(jù)通常是以字符串形式存在的,使用datetime對象會更加方便,所以本文給大家總結(jié)Python將字符串轉(zhuǎn)換為datetime對象的五種方法
    2025-07-07
  • kali中python版本的切換方法

    kali中python版本的切換方法

    今天小編就為大家分享一篇kali中python版本的切換方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • PyTorch如何使用embedding對特征向量進(jìn)行嵌入

    PyTorch如何使用embedding對特征向量進(jìn)行嵌入

    這篇文章主要介紹了PyTorch如何使用embedding對特征向量進(jìn)行嵌入問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 如何利用python正則表達(dá)式匹配版本信息

    如何利用python正則表達(dá)式匹配版本信息

    這篇文章主要給大家介紹了關(guān)于如何利用python正則表達(dá)式匹配版本信息的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Python從入門到實(shí)戰(zhàn)之?dāng)?shù)據(jù)結(jié)構(gòu)篇

    Python從入門到實(shí)戰(zhàn)之?dāng)?shù)據(jù)結(jié)構(gòu)篇

    數(shù)據(jù)結(jié)構(gòu)中有很多樹的結(jié)構(gòu),其中包括二叉樹、二叉搜索樹、2-3樹、紅黑樹等等。本文中對數(shù)據(jù)結(jié)構(gòu)進(jìn)行了總結(jié),不求嚴(yán)格精準(zhǔn),但求簡單易懂
    2021-11-11
  • Python字符串中刪除特定字符的方法

    Python字符串中刪除特定字符的方法

    這篇文章主要介紹了Python字符串中刪除特定字符的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • python中的split()函數(shù)和os.path.split()函數(shù)使用詳解

    python中的split()函數(shù)和os.path.split()函數(shù)使用詳解

    今天小編就為大家分享一篇python中的split()函數(shù)和os.path.split()函數(shù)使用詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12

最新評論

乐山市| 内丘县| 镇远县| 遵化市| 大港区| 高要市| 安西县| 富锦市| 鄂伦春自治旗| 玉屏| 馆陶县| 阿克| 隆德县| 姜堰市| 西乌| 永济市| 长葛市| 安义县| 都安| 上高县| 台东市| 偃师市| 天镇县| 咸丰县| 宜章县| 定安县| 孟州市| 霍林郭勒市| 吉水县| 涞水县| 宝兴县| 麟游县| 高淳县| 惠水县| 灌南县| 儋州市| 伊春市| 蒙山县| 建阳市| 紫云| 综艺|