本文目錄一覽:
為什麼python多線程這麼慢
差不多是這樣子。多線程目前僅用於網路多線程採集, 以及性能測試。
其它的語言也有類似的情況,線程本身的特點導致線程的適用範圍是受限的。只有CPU過剩,而其它的任務很慢,此時用線程才是有益的,可以很好平衡等待時間,提高並發性能。
線程的問題主要是線程的安全穩定性。線程無法強制中止,同時線程與主進程共享內存,可能會影響主進程的內存管理。
在python里線程出問題,可能會導致主進程崩潰。 雖然python里的線程是操作系統的真實線程。
那麼怎麼解決呢?通過我們用進程方式。子進程崩潰後,會完全的釋放所有的內存和錯誤狀態。所以進程更安全。 另外通過進程,python可以很好的繞過GIL,這個全局鎖問題。
但是進程也是有局限的。不要建立超過CPU總核數的進程,否則效率也不高。
簡單的總結一下。
當我們想實現多任務處理時,首先要想到使用multiprocessing, 但是如果覺著進程太笨重,那麼就要考慮使用線程。 如果多任務處理中需要處理的太多了,可以考慮多進程,每個進程再採用多線程。如果還處理不要,就要使用輪詢模式,比如使用poll event, twisted等方式。如果是GUI方式,則要通過事件機制,或者是消息機制處理,GUI使用單線程。
所以在python里線程不要盲目用, 也不要濫用。 但是線程不安全是事實。如果僅僅是做幾個後台任務,則可以考慮使用守護線程做。如果需要做一些危險操作,可能會崩潰的,就用子進程去做。 如果需要高度穩定性,同時並發數又不高的服務。則強烈建議用多進程的multiprocessing模塊實現。
在linux或者是unix里,進程的使用代價沒有windows高。還是可以接受的。
為什麼有人說 Python 的多線程是雞肋
因為 Python 中臭名昭著的 GIL。
那麼 GIL 是什麼?為什麼會有 GIL?多線程真的是雞肋嗎? GIL 可以去掉嗎?帶著這些問題,我們一起往下看,同時需要你有一點點耐心。
多線程是不是雞肋,我們先做個實驗,實驗非常簡單,就是將數字 「1億」 遞減,減到 0 程序就終止,這個任務如果我們使用單線程來執行,完成時間會是多少?使用多線程又會是多少?show me the code
單線程
在我的4核 CPU 計算機中,單線程所花的時間是 6.5 秒。可能有人會問,線程在哪裡?其實任何程序運行時,默認都會有一個主線程在執行。(關於線程與進程這裡不展開,我會單獨開一篇文章)
多線程
創建兩個子線程 t1、t2,每個線程各執行 5 千萬次減操作,等兩個線程都執行完後,主線程終止程序運行。結果,兩個線程以合作的方式執行是 6.8 秒,反而變慢了。按理來說,兩個線程同時並行地運行在兩個 CPU 之上,時間應該減半才對,現在不減反增。
是什麼原因導致多線程不快反慢的呢?
原因就在於 GIL ,在 Cpython 解釋器(Python語言的主流解釋器)中,有一把全局解釋鎖(Global Interpreter Lock),在解釋器解釋執行 Python 代碼時,先要得到這把鎖,意味著,任何時候只可能有一個線程在執行代碼,其它線程要想獲得 CPU 執行代碼指令,就必須先獲得這把鎖,如果鎖被其它線程佔用了,那麼該線程就只能等待,直到佔有該鎖的線程釋放鎖才有執行代碼指令的可能。
因此,這也就是為什麼兩個線程一起執行反而更加慢的原因,因為同一時刻,只有一個線程在運行,其它線程只能等待,即使是多核CPU,也沒辦法讓多個線程「並行」地同時執行代碼,只能是交替執行,因為多線程涉及到上線文切換、鎖機制處理(獲取鎖,釋放鎖等),所以,多線程執行不快反慢。
什麼時候 GIL 被釋放呢?
當一個線程遇到 I/O 任務時,將釋放GIL。計算密集型(CPU-bound)線程執行 100 次解釋器的計步(ticks)時(計步可粗略看作 Python 虛擬機的指令),也會釋放 GIL。可以通過設置計步長度,查看計步長度。相比單線程,這些多是多線程帶來的額外開銷
CPython 解釋器為什麼要這樣設計?
多線程是為了適應現代計算機硬體高速發展充分利用多核處理器的產物,通過多線程使得 CPU 資源可以被高效利用起來,Python 誕生於1991年,那時候硬體配置遠沒有今天這樣豪華,現在一台普通伺服器32核64G內存都不是什麼司空見慣的事
但是多線程有個問題,怎麼解決共享數據的同步、一致性問題,因為,對於多個線程訪問共享數據時,可能有兩個線程同時修改一個數據情況,如果沒有合適的機制保證數據的一致性,那麼程序最終導致異常,所以,Python之父就搞了個全局的線程鎖,不管你數據有沒有同步問題,反正一刀切,上個全局鎖,保證數據安全。這也就是多線程雞肋的原因,因為它沒有細粒度的控制數據的安全,而是用一種簡單粗暴的方式來解決。
這種解決辦法放在90年代,其實是沒什麼問題的,畢竟,那時候的硬體配置還很簡陋,單核 CPU 還是主流,多線程的應用場景也不多,大部分時候還是以單線程的方式運行,單線程不要涉及線程的上下文切換,效率反而比多線程更高(在多核環境下,不適用此規則)。所以,採用 GIL 的方式來保證數據的一致性和安全,未必不可取,至少在當時是一種成本很低的實現方式。
那麼把 GIL 去掉可行嗎?
還真有人這麼干多,但是結果令人失望,在1999年Greg Stein 和Mark Hammond 兩位哥們就創建了一個去掉 GIL 的 Python 分支,在所有可變數據結構上把 GIL 替換為更為細粒度的鎖。然而,做過了基準測試之後,去掉GIL的 Python 在單線程條件下執行效率將近慢了2倍。
Python之父表示:基於以上的考慮,去掉GIL沒有太大的價值而不必花太多精力。
你在公司里用python嗎?都是什麼情況下用?
我會用一些python,有時候寫腳本的時候會用到,還有在做大數據分析的時候用,也就是python spark,另外,自己做一些機器學習的時候也會用。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/180388.html