Python 多線程無用?深刻總結 二(深刻了解GIL 線程守護 線程進程CPU關係)

知識都是由淺入深的過程,以前看的書比較淺,知識表面上使用下多線程,對多線程編程的一些細節說的略淺。在後來的學習中,發現了遺漏了一些details的問題特此補上python

1.threading.Tread()直接建立線程實例與threading.start_new_thread()的區別是什麼?

答:

最大的區別就是,若是直接new新的線程,那麼程序運行到了new_thread會直接開始運行線程。可是實例化thread會在實例化結束後,有start命令後纔開始運行線程,因此咱們使用了threading.Thread()。編程

2.join(timeout=)與setDaemon

join(timeout=),這個方法爲threading module比thread module多的方法,也是推薦使用threading的緣由:因爲threading module中有線程守護機制,運行 thread1.join()安全

那麼thread1線程會被守護,其意思就是等待thread1執行完或者在timeout參數規定的等待時間內,thread1一直在執行的。可是若是在thread module裏面若是想完成這樣的功能,就須要引入鎖的概念(分配、獲取、釋放、檢查鎖狀態等),很明顯就太麻煩了。多線程

對於join()方法而言,其另一個重要方面是其實他根本不須要調用。一旦線程啓動,他們就會一直執行,知道給定的函數完成後退出。若是主線程還有其餘事情去作,而不是等待這些線程完成(例如處理新的用戶請求),就能夠不調用join().join方法只有在你須要等待線程完成的時候纔是有用的。函數

思辨性能

咱們在使用Python時候說的主線程,能夠理解爲python程序,即主線程,python程序coding中啓動的線程能夠視爲子線程。學習

主進程的子進程或者線程,若是被set爲守護線程或者進程那麼,等待主進程或者線程執行完畢後,其子線程或者進程就直接被銷燬,不會等到其執行完畢後再結束主進程。操作系統

圖例中並無設置守護線程或者等待線程。 可是若是我在子線程後加了join等待線程的話結果以下線程

此時果真主線程等待子線程執行結束後再開始執行(可理解爲懸停)code

此例子爲守護線程的例子,如圖所示,start前面設置了子線程爲守護線程那麼,主線程結束,子線程也被迫結束。

注:

主線程在其餘非守護線程結束後,纔算真正結束。由於主線程結束,意味着進程結束,因此操做系統給進程分配的資源都要被收回,因此必須確保非守護線程運行完畢。

3 GIL:

首先須要明確的一點是GIL並非Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。 就比如C++是一套語言(語法)標準,可是能夠用不一樣的編譯器來編譯成可執行代碼。有名的編譯器例如GCC,INTEL C++,Visual C++等。Python也同樣,一樣一段代碼能夠經過CPython,PyPy,Psyco等不一樣的Python執行環境來執行。像其中的JPython就沒有GIL。然而由於CPython是大部分環境下默認的Python執行環境。因此在不少人的概念裏CPython就是Python,也就想固然的把GIL歸結爲Python語言的缺陷。因此這裏要先明確一點:GIL並非Python的特性,Python徹底能夠不依賴於GIL.

介紹:

GIL本質上就是一把互斥鎖,既然是互斥鎖那麼都是將並行變爲串行,從而保證同一時間內數據只能被一個任務修改,進而保證數據安全。每次執行python程序的時候,都會產生一個獨立的進程。例如python a.py b.py c.py,這樣就啓動了三個不一樣的python。

那麼對於一個進程中,含有主線程,還含有其餘由於主線程開啓的線程,還有解釋器開啓的垃圾回收等解釋器級別的線程,總之,全部線程都運行在這個進程內。

實驗

在一個python腳本中定義一個函數work,啓動三個線程訪問它(target=work),若是能夠調用,咱們就能夠理解爲線程訪問成功。,這個coding是線程池中共享的。

多個線程target=work,那麼執行流程就是每個線程拿到執行權限,而後交到解釋器中去解釋。 那麼這就致使了一個問題,同一行數據100,那麼線程執行x=100的時候,垃圾回收線程要收回x=100,以下加GIL鎖,保證python解釋器同一時間執行一個任務代碼。

4 Python 多線程到底有用嗎?

先思考三個問題:

1.CPU是用來幹嗎的(計算仍是I/O)?

2.多cpu,意味着能夠有多個核並行完成計算,因此多核提高的是計算性能。

  1. 每一個cpu一旦遇到I/O阻塞,仍然須要等待,因此多核對I/O操做沒什麼用處 。

舉一個例子,計算至關於吃飯,CPU至關於一我的,那麼咱們一我的吃飯快,仍是多我的吃飯快?固然是多我的,因此多個CPU是性能提高。I/O阻塞至關於,上菜阻塞,那麼若是是I/O密集型的飯局,一隻不上菜,叫一票人也沒用。反過來說若是上菜充足,那固然是人越多越好。

因此對於計算來講CPU越多越好,可是對於I/O來講,再多CPU也沒用,固然對於一個python程序來講CPU多,確定執行效率會有所提升。由於一個py程序並非純計算或者是I/O密集的程序,因此只能去看程序是I/O密集型的仍是計算密集的。

案例:若是咱們有四個任務須要處理,那麼:

解決方案

1.四個進程

2.一個進程:下四個線程

單核狀況下:

1.若是四個任務是計算密集型,沒有多核來並行計算,方案一徒增了建立進程的開銷,方案二勝 2.若是四個任務是I/O密集型,方案一建立進程的開銷大,且進程的切換速度遠不如線程,方案二勝

多核狀況下:

1.若是四個任務是計算密集型,多核意味着並行計算,在python中一個進程中同一時刻只有一個線程執行用不上多核,方案一勝 2.若是四個任務是I/O密集型,再多的核也解決不了I/O問題,方案二勝

結論

如今電腦都是多核的,對於計算密集型的多線程並無多大的提高性能,可是若是是I/O密集性,多線程仍是有顯著的提高的。

相關文章
相關標籤/搜索