Python多線程(一):GIL

最近在學(xué)習(xí)Python的多線程編程邮丰,寫幾篇文章記錄一下吻商。

GIL是Global Interpreter Lock,即全局解釋鎖的縮寫漱凝,保證了了同一時(shí)刻只有一個(gè)線程在一個(gè)CPU上執(zhí)行字節(jié)碼纸兔,無法將多個(gè)線程映射到多個(gè)CPU上惰瓜。這是CPython解釋器的缺陷,由于CPython是大部分環(huán)境下默認(rèn)的Python執(zhí)行環(huán)境汉矿,而很多庫都是基于CPython編寫的崎坊,因此很多人將GIL歸結(jié)為Python的問題。

GIL被設(shè)計(jì)來保護(hù)線程安全洲拇,由于多線程共享變量奈揍,如果不能很好的進(jìn)行線程同步,多線程非常容易將線程改亂赋续。實(shí)際上即使有了GIL男翰,這個(gè)問題也無法完全解決,因?yàn)镚IL實(shí)際上也會(huì)釋放纽乱,而且它并不是在某個(gè)線程執(zhí)行完成后才釋放蛾绎,而是根據(jù)代碼的字節(jié)碼或者時(shí)間片進(jìn)行釋放,下面是一個(gè)例子:

import threading

total = 0
def add():
    global total
    for i in range(1000000):
        total += 1

def desc():
    global total
    for i in range(1000000):
        total -= 1

thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()

print(total)

這個(gè)程序直觀來看迫淹,是將total加1000000減1000000秘通,不管哪個(gè)線程先執(zhí)行为严,最后的結(jié)果應(yīng)該都是0才對敛熬,但是如果允許你該上面的代碼多次,就會(huì)發(fā)現(xiàn)每次代碼的結(jié)果都不一樣第股,有正有負(fù)应民。這其中的原因就涉及到了GIL的釋放。我們首先可以查看一下普通加法函數(shù)的字節(jié)碼:

import dis
def add1(a):
    a += 1
    return a
print(dis.dis(add1))

結(jié)果如下:

  2           0 LOAD_FAST                0 (a)
              2 LOAD_CONST               1 (1)
              4 INPLACE_ADD
              6 STORE_FAST               0 (a)

  3           8 LOAD_FAST                0 (a)
             10 RETURN_VALUE
None

可以看到a += 1的執(zhí)行過程是先將變量a裝載進(jìn)CPU,再將常量1裝載進(jìn)CPU诲锹,然后執(zhí)行相加操作繁仁,最后再將a存儲(chǔ)在內(nèi)存中。由于GIL不是根據(jù)Python代碼段來釋放归园,而是根據(jù)字節(jié)碼或者時(shí)間片來釋放的黄虱,在之前的例子中,如果add函數(shù)在進(jìn)行加法后還未在內(nèi)存中保存庸诱,GIL釋放捻浦,desc函數(shù)獲得執(zhí)行權(quán),此時(shí)它進(jìn)行裝載時(shí)裝載的變量total是未進(jìn)行加法操作的total桥爽,因此相當(dāng)于之前的add函數(shù)失去了作用朱灿,在進(jìn)行多次循環(huán)后,程序的運(yùn)行結(jié)果自然不為0钠四。這種情況稱為競態(tài)條件(race condition)盗扒,即使沒有GIL,也會(huì)出現(xiàn)這種問題缀去。解決方法是使用鎖機(jī)制侣灶,將會(huì)在后面的文章中提到。

還有一種條件會(huì)導(dǎo)致GIL釋放朵耕,那就是當(dāng)程序遇到IO操作和time.sleep將程序阻塞的時(shí)候,因此多線程對于處理IO操作的問題非常有效阎曹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末处嫌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子檐薯,更是在濱河造成了極大的恐慌坛缕,老刑警劉巖捆昏,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骗卜,死亡現(xiàn)場離奇詭異,居然都是意外死亡举户,警方通過查閱死者的電腦和手機(jī)俭嘁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屯远,“玉大人慨丐,你說我怎么就攤上這事泄私∩味耍” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長梧奢。 經(jīng)常有香客問我演痒,道長鸟顺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮莉掂,結(jié)果婚禮上渐裸,老公的妹妹穿的比我還像新娘昏鹃。我一直安慰自己,他們只是感情好阅嘶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布讯柔。 她就那樣靜靜地躺著护昧,像睡著了一般惋耙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上湿酸,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天推溃,我揣著相機(jī)與錄音届腐,去河邊找鬼犁苏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛襟铭,可吹牛的內(nèi)容都是我干的寒砖。 我是一名探鬼主播嫉拐,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼漠嵌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了化撕?” 一聲冷哼從身側(cè)響起植阴,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對情侶失蹤掠手,失蹤者是張志新(化名)和其女友劉穎狸捕,沒想到半個(gè)月后灸拍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捌刮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舒岸。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俄认,死狀恐怖洪乍,靈堂內(nèi)的尸體忽然破棺而出壳澳,到底是詐尸還是另有隱情,我是刑警寧澤萎津,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布荤傲,位于F島的核電站部念,受9級(jí)特大地震影響儡炼,放射性物質(zhì)發(fā)生泄漏乌询。R本人自食惡果不足惜妹田,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一鬼佣、第九天 我趴在偏房一處隱蔽的房頂上張望晶衷。 院中可真熱鬧晌纫,春花似錦永丝、人聲如沸慕嚷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纺涤。三九已至,卻和暖如春崎脉,著一層夾襖步出監(jiān)牢的瞬間囚灼,已是汗流浹背灶体。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留樟结,地道東北人瓢宦。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓刁笙,卻偏偏與公主長得像疲吸,于是被迫代替她去往敵國和親摘悴。 傳聞我的和親對象是個(gè)殘疾皇子舰绘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容