Python 的多線程是雞肋?


“唉,還沒畢業就受到甲方的支配,等以后進了公司可咋整啊。”小白嘴里這么吐槽,但心理上還是不敢怠慢,只能戀戀不舍地關掉眼前的游戲,打開了 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,互不干擾,自然就能完成並發了。

“這個方法聽起來才正常嘛,我馬上就回去試試,謝謝你了!”


希望你在看完我的文章之后有所收獲~(求點贊吶!)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM