線程-Thread
進程是計算機中最小的資源分配單位,創建一個進程,操作系統需要向其分配一定的內存資源。所以進程對于操作系統來說還是有一定的負擔。
線程是計算機中被CPU調度的最小單位,進程中的代碼是由線程來完成的,每個進程可以有多個線程,但是至少要有一個線程。
線程是一個輕量級概念,它沒有屬于自己的資源。同一個進程中的所有的線程的資源是共享的。在Python中,一個進程中的多個線程無法并行,只能并發執行(Java,C++, C#等C語言中是可以的),主要是因為Python屬于解釋型語言,而Java,C語言屬于編譯型語言,Python中有獨有的GIL(Global Interpreter Lock)全局解釋器鎖。
編譯型語言:程序在執行之前需要一個專門的編譯過程,把程序編譯成 為機器語言的文件,運行時不需要重新翻譯,直接使用編譯的結果就行了。而相對的,解釋性語言編寫的程序不進行預先編譯,以文本方式存儲程序代碼。在發布程序時,看起來省了道編譯工序。但是,在運行程序的時候,解釋性語言必須先解釋再運行。
線程和進程之間的區別主要在于:
占用的資源
調度的效率
資源是否共享
創建線程與創建進程的操作幾乎相同:
為什么說線程是輕量級的概念呢?
結果顯而易見的。
守護線程-setDaemon
守護線程是指在程序運行的時候在后臺提供一種通用服務的線程。
守護線程的特性在進程中已經有過闡述,守護線程和守護進程其實差不多,但還是有些許差別:
從結果可以看出,守護線程并沒有像進程一樣,在主進程的代碼結束之后便結束,反而等全部線程執行完畢之后再結束。因為在同一個進程中,多個線程的資源是共享的,因此守護線程的守護對象應該是全部線程而不是進程(進程的代碼也要靠線程來執行)
當同時滿足以下兩個條件時,就會出現線程的安全問題①多個線程在操作共享的數據;②操作共享數據的線程代碼有多條。
舉例:
從一百到十萬結果基本上都是0,但是當循環次數擴大到100萬的時候,問題就開始顯現了:
和進程修改共享數據的原理是一樣的,多個線程多個代碼對同一個共享數據進行修改,次數足夠大時難免會出現同時操作的現象,自然而然就會產生數據的誤差的問題。所以可以引入線程鎖Lock的概念方法,進程鎖Lock的原理為同一時刻只允許一個進程對數據進行修改,線程鎖Lock的原理就是同一時刻只允許一個線程對數據進行修改。
這樣就保護了數據安全,但是時間相對來說就長了很多很多
遞歸鎖-RLock
遞歸鎖的講解需要引入“哲學家吃面問題”
所謂哲學家吃面問題就是每個哲學家必須要搶到叉子和面條才能夠繼續使程序繼續進程,否則程序就會陷入死鎖狀態。也就是有兩把鎖,線程需要同時拿到兩把才能夠程序繼續運行,否則一把鎖被一個線程拿到,另一把鎖被另一個線程拿到,這樣兩把鎖就無法同時解鎖,就進入死鎖狀態。
寫一個死鎖程序:
當eat1激活了noodle_lock之后,eat2的noodle_lock必須等到ea1釋放才能激活。而eat1代碼順序為先面條后叉子,eat2代碼順序為先叉子后面條,所以在相同反應的情況下,哲學家2搶到面條的同時,哲學家3搶到了叉子,兩個人同時搶到更靠近自己的東西,誰也不放手,表現為程序無法進行下去,也就是死鎖現象。(為什么要用eat1和eat2兩個方法,而不是只用eat1一個方法?是因為需要有一個偏向值,eat1更偏向面條,所以哲學家1和2更容易搶到面條,eat2更偏向叉子,所以哲學家3和4更容易搶到叉子。如果只用一個eat,那么表現為哲學家們按順序吃面條(同步))
而且解鎖的順序也頗為講究,采用后進先出法,具體表現為以下的圖,第一道門開了鎖進去,再開第二道鎖再進去,那么出來的時候需要鎖門,鎖門就要先鎖里面的門,不然都出來了還怎么鎖里面的門呢?
為了解決死鎖現象,threading模塊中還提供了RLock遞歸鎖的方法,
當多個線程同時搶多把鎖的時候就會出現死鎖的現象。其實遞歸鎖也不是一個很好地解決方案,死鎖現象的發生不是互斥鎖的原因,而是程序猿/媛的邏輯出現了問題。
審核編輯:劉清
-
cpu
+關注
關注
68文章
10901瀏覽量
212640 -
計算機
+關注
關注
19文章
7532瀏覽量
88432 -
操作系統
+關注
關注
37文章
6882瀏覽量
123581 -
C語言
+關注
關注
180文章
7614瀏覽量
137407 -
線程
+關注
關注
0文章
505瀏覽量
19722
發布評論請先 登錄
相關推薦
評論