為什麼有人說 Python 多執行緒是雞肋?

2021-08-21 10:20:35 字數 2400 閱讀 8036

為什麼有人會說 python 多執行緒是雞肋?知乎上有人提出這樣乙個問題,在我們常識中,多程序、多執行緒都是通過併發的方式充分利用硬體資源提高程式的執行效率,怎麼在 python 中反而成了雞肋?

有同學可能知道答案,因為 python 中臭名昭著的 gil,gil 是什麼?為什麼會有 gil?多線**的是雞肋嗎? gil 可以去掉嗎?帶著這些問題,我們一起往下看,同時需要你有一點點耐心。

多執行緒是不是雞肋,我們先做個實驗,實驗非常簡單,就是將數字 「1億」 遞減,減到 0 程式就終止,這個任務如果我們使用單執行緒來執行,完成時間會是多少?使用多執行緒又會是多少?show me the code

# 任務

def decrement(n):

while n > 0:

n -= 1

單執行緒

import time

start = time.time()

decrement(100000000)

cost = time.time() - start

>>> 6.541690826416016

在我的4核 cpu 計算機中,單執行緒所花的時間是 6.5 秒。可能有人會問,執行緒在**?其實任何程式執行時,預設都會有乙個主線程在執行。(關於執行緒與程序這裡不展開,我會單獨開一篇文章)

多執行緒

import threading

start = time.time()

t1 = threading.thread(target=decrement, args=[50000000])

t2 = threading.thread(target=decrement, args=[50000000])

t1.start() # 啟動執行緒,執行任務

t2.start() # 同上

t1.join() # 主線程阻塞,直到t1執行完成,主線程繼續往後執行

t2.join() # 同上

cost = time.time() - start

>>>6.85541033744812

建立兩個子執行緒 t1、t2,每個執行緒各執行 5 千萬次減操作,等兩個執行緒都執行完後,主線程終止程式執行。結果,兩個執行緒以合作的方式執行是 6.8 秒,反而變慢了。按理來說,兩個執行緒同時並行地執行在兩個 cpu 之上,時間應該減半才對,現在不減反增。

是什麼原因導致多執行緒不快反慢的呢?

因此,這也就是為什麼兩個執行緒一起執行反而更加慢的原因,因為同一時刻,只有乙個執行緒在執行,其它執行緒只能等待,即使是多核cpu,也沒辦法讓多個執行緒「並行」地同時執行**,只能是交替執行,因為多執行緒涉及到上線文切換、鎖機制處理(獲取鎖,釋放鎖等),所以,多執行緒執行不快反慢。

什麼時候 gil 被釋放呢?

當乙個執行緒遇到 i/o 任務時,將釋放gil。計算密集型(cpu-bound)執行緒執行 100 次直譯器的計步(ticks)時(計步可粗略看作 python 虛擬機器的指令),也會釋放 gil。可以通過sys.setcheckinterval()設定計步長度,sys.getcheckinterval()檢視計步長度。相比單執行緒,這些多是多執行緒帶來的額外開銷

cpython 直譯器為什麼要這樣設計?

多執行緒是為了適應現代計算機硬體高速發展充分利用多核處理器的產物,通過多執行緒使得 cpu 資源可以被高效利用起來,python 誕生於2023年,那時候硬體配置遠沒有今天這樣豪華,現在一台普通伺服器32核64g記憶體都不是什麼司空見慣的事,但是多執行緒有個問題,怎麼解決共享資料的同步、一致性問題,因為,對於多個執行緒訪問共享資料時,可能有兩個執行緒同時修改乙個資料情況,如果沒有合適的機制保證資料的一致性,那麼程式最終導致異常,所以,python之父就搞了個全域性的執行緒鎖,不管你資料有沒有同步問題,反正一刀切,上個全域性鎖,保證資料安全。這也就是多執行緒雞肋的原因,因為它沒有細粒度的控制資料的安全,而是用一種簡單粗暴的方式來解決。

這種解決辦法放在90年代,其實是沒什麼問題的,畢竟,那時候的硬體配置還很簡陋,單核 cpu 還是主流,多執行緒的應用場景也不多,大部分時候還是以單執行緒的方式執行,單執行緒不要涉及執行緒的上下文切換,效率反而比多執行緒更高(在多核環境下,不適用此規則)。所以,採用 gil 的方式來保證資料的一致性和安全,未必不可取,至少在當時是一種成本很低的實現方式。

那麼把 gil 去掉可行嗎?

還真有人這麼干多,但是結果令人失望,在2023年greg stein 和mark hammond 兩位哥們就建立了乙個去掉 gil 的 python 分支,在所有可變資料結構上把 gil 替換為更為細粒度的鎖。然而,做過了基準測試之後,去掉gil的 python 在單執行緒條件下執行效率將近慢了2倍。

python之父表示:基於以上的考慮,去掉gil沒有太大的價值而不必花太多精力。

為什麼要用多執行緒

以前我認為多執行緒的作用就是提公升效能。實際上,多執行緒並不一定能提公升效能 甚至還會降低效能 多執行緒也不只是為了提公升效能。多執行緒主要有以下的應用場景 1 避免阻塞 非同步呼叫 單個執行緒中的程式,是順序執行的。如果前面的操作發生了阻塞,那麼就會影響到後面的操作。這時候可以採用多執行緒,我感覺...

為什麼要用多執行緒

1 避免阻塞 非同步呼叫 2 避免cpu空轉 需要處理的資訊提供得太慢,導致 cpu 效能沒有充分利用,這個時候多程序能充分利用 cpu 在io程式設計一節中,我們已經知道,cpu的速度遠遠快於磁碟 網路等io。在乙個執行緒中,cpu執行 的速度極快,然而,一旦遇到io操作,如讀寫檔案 傳送網路資料...

為什麼使用多執行緒

1 耗時的操作使用執行緒,提高應用程式響應 2 並行操作時使用執行緒,如c s架構的伺服器端併發執行緒響應使用者的請求。3 多cpu系統中,使用執行緒提高cpu利用率 4 改善程式結構。乙個既長又複雜的程序可以考慮分為多個執行緒,成為幾個獨立或半獨 立的執行部分,這樣的程式會利於理解和修改。使用多執...