Python 的多執行緒是雞肋?
- 2019 年 10 月 31 日
- 筆記

「唉,還沒畢業就受到甲方的支配,等以後進了公司可咋整啊。」小白嘴裡這麼吐槽,但心理上還是不敢怠慢,只能戀戀不捨地關掉眼前的遊戲,打開了 Python 程式碼思考了起來。
「現在的程式是單執行緒的,那就用多執行緒模型來優化吧,嘿嘿,我太機智了!」小白打心底感謝前段時間裡學習到的執行緒的知識。「Python 里好像是 threading 模組負責多執行緒的,就決定是你了,threading !」
花了兩三個小時,小白終於把程式改好了,他長舒一口氣,點擊 Run ,開始測試運行時間。
「woc!怎麼運行時間還變長了?」看著螢幕上顯示的測試結果,小白傻眼了,這多執行緒怎麼不頂用?自己明明是按官方文檔來的啊!
debug 無果,小白只好尋求好朋友小明的幫助。
「哈哈哈,你居然用 python 的多執行緒?你不知道 python 的多執行緒被很多人稱作「雞肋」嗎?」
「啊,不會吧?還有這種說法?我要是知道我肯定就不用多執行緒來改了。。。可為什麼 python 的多執行緒就雞肋了?那多執行緒爬蟲是怎麼回事?」
「我先給你解釋下 python 下的多執行緒是怎麼一回事吧。Python 是一門解釋型語言,它的執行是由解釋器來控制的,我們一般都會使用默認的 Cpython 解釋器,這些我想你應該清楚。」
「那當然,這在一開始學 Python 的時候老師就講過了。」
「那你知不知道什麼是 GIL?」小明問道。
小白撓撓頭,尷尬的回答:「我沒聽說過。」
「也是,你要是知道 GIL ,就能弄明白 Python 的多執行緒了。GIL,全稱是 Global Interpreter Lock ,全局解釋鎖 ,專門給解釋器用的。」
「蛤?解釋器還要需要鎖? 」
「這個鎖別有妙用,讓我先考考你,C 語言能不能在用戶態下做到執行緒級別的時間片輪轉?」
「不能!作業系統里講過了,我還記得上次你教我的內容~」小白得意的回答。
關於執行緒,詳細的在這裡:https://www.cnblogs.com/tobe98/p/11651237.html
「但是 python 能做到!python 里,解釋器可以記錄每一個執行緒執行了多長時間——時間一到,就能夠切換到另一條執行緒。」
「有點意思,聽起來像是解釋器充當了作業系統的角色,然後為 python 執行緒提供了時間片輪轉的能力。」
tobe 註:理論上 C 語言也可以做到,畢竟 python 解釋器就是用 C 語言寫的。
「解釋的很到位,我再說回 GIL 吧,在多核還沒有出現的時候,就已經有執行緒的存在了,GIL 就是拿來給執行緒加鎖的,當一個執行緒將要執行時,解釋器會把 GIL 鎖給這個執行緒,其他執行緒因為沒有鎖,是無法運行的。等到持有鎖執行緒阻塞或者運行 100 個位元組碼,解釋器就會把鎖交給其他執行緒。」

「但是這個 GIL 鎖是全局(Global)的,也就導致即使是多核情況下,一次也只有一個執行緒能運行,從整體上看,整個程式是串列的。」
小白恍然大悟:「怪不得我的程式還變慢了,原來 python 的多執行緒不僅不能利用多核,還因為執行緒切換拖慢了我程式的執行速度!我想很多人應該都遇到過我這個問題吧,Python 社區為什麼不修改這一特性,讓多執行緒也做到並行呢?」
小明嘆了口氣:「哪有這麼簡單,修改鎖的設計是很難的,我聽說 MYSQL 拆分 buffer pool mutex 這個全局鎖花了好多年呢。不過 Python 社區為此還是做了不少挽救工作的,比如在執行緒睡覺(sleep),等待連接的時候主動釋放 GIL,讓其他執行緒繼續執行。拿爬蟲程式來說吧,單個爬蟲總會花時間在下載網頁上,很多 CPU 時間就浪費掉了, 提供 sleep 機制後,這些爬蟲可以在等待下載時釋放 GIL 鎖,把機會讓給其他爬蟲,這樣整體運行速度能夠得到大幅提升。」
「我好像明白了,」小白感覺自己被打通了任督二脈:「也就是說 Python 的多執行緒適合 I/O 密集型的程式,但是對計算密集型程式就不那麼友好了~ 誒等等,那我怎麼辦?我還打算用多執行緒優化我的程式呢!」
「讓 python 利用多核的方法還是有的,比如說,讓 python 調用 C 語言的程式碼,在 C 語言里實現多執行緒,因為 C 語言里沒有 GIL 鎖,這些執行緒不會受到 GIL 的約束,也就能並行了。」

小白一個勁兒搖頭:「不不不不不,好不容易寫完的 Python 程式碼,你讓我改成 C?這不是要我的命嗎!我拒絕!」
「這不是還有第二種方法嘛——使用多進程,Python 里有個 multiprocessing 模組,可以創建多個進程,因為不同的進程使用不同的解釋器,所以它們有各自的 GIL,互不干擾,自然就能完成並發了。「
「這個方法聽起來才正常嘛,我馬上就回去試試,謝謝你了!」
希望你在看完我的文章之後有所收穫~(求點贊吶!)

