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