多核CPU
多核心cpu主要分原生多核和封裝多核。原生多核指的是真正意義上的多核,最早由AMD提出,每個核心之間都是完全獨立的,都擁有自己的前端總線,不會造成沖突,即使在高負(fù)載狀況下,每個核心都能保證自己的性能不受太大的影響,通俗的說,原生多核的抗壓能力強,但是需要先進(jìn)的工藝,每擴(kuò)展一個核心都需要很多的研發(fā)時間。封裝多核是只把多個核心直接封裝在一起,比如Intel早期的PD雙核系列,就是把兩個單核直接封裝在一起,和原生的比起來還是差了很多,而且后者成本比較高,優(yōu)點在于多核心的發(fā)展要比原生快的多。
多進(jìn)程
Windows 應(yīng)用程序中消息有兩種送出途徑;直接和排隊。Windows或某些運行的應(yīng)用程序可直接發(fā)布消息給窗口過程,或者,消息可送到消息列象連續(xù)不斷輪詢消息隊列的OS中當(dāng)前執(zhí)行的每個進(jìn)程都 事件驅(qū)動程序不是由事件的順序來控制,而是由事件的發(fā)生來控,而事件的發(fā)生是隨機(jī)的、不確定的,這就允許程序的用戶用各種合理的順序來安排程序的流程。
多線程
線程(英語:multithreading),是指從軟件或者硬件上實現(xiàn)多個線程并發(fā)執(zhí)行的技術(shù)。具有多線程能力的計算機(jī)因有硬件支持而能夠在同一時間執(zhí)行多于一個線程,進(jìn)而提升整體處理性能。具有這種能力的系統(tǒng)包括對稱多處理機(jī)、多核心處理器以及芯片級多處理(Chip-level multithreading)或同時多線程(Simultaneous multithreading)處理器。在一個程序中,這些獨立運行的程序片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理(Multithreading)”。具有多線程能力的計算機(jī)因有硬件支持而能夠在同一時間執(zhí)行多于一個線程(***譯作“執(zhí)行緒”),進(jìn)而提升整體處理性能。
多核CPU、多進(jìn)程、多線程之間的聯(lián)系解析
多道程序設(shè)計
在進(jìn)程執(zhí)行過程中常常會因為資源請求或者IO被阻塞或中斷(有的請求或者中斷需要處理很長時間),此時CPU便空閑出來,眾所周知,CPU是計算機(jī)中非常寶貴的資源,為提高其利用率,操作系統(tǒng)需通過進(jìn)程切換,將CPU交給就緒隊列的某個進(jìn)程使用;等上次被阻塞或者中端的進(jìn)程再次滿足執(zhí)行條件(一般是請求的資源得到滿足或者IO完成等)后,操作系統(tǒng)便通過調(diào)度算法將CPU再次交給該進(jìn)程執(zhí)行任務(wù),其中操作系統(tǒng)的進(jìn)程調(diào)度算法有多種(例如在交互式系統(tǒng)(windows)中的進(jìn)程調(diào)度算法有時間片輪轉(zhuǎn)調(diào)度、優(yōu)先級調(diào)度、多級隊列調(diào)度等,這些相信大家都很熟悉了,此處不再進(jìn)一步闡述),具體選擇依賴操作系統(tǒng)。這時從用戶的角度感覺是多個進(jìn)程在同時執(zhí)行,這的易于操作系統(tǒng)通過進(jìn)程調(diào)度將一個cpu變成多個虛擬的CPU,實現(xiàn)多個進(jìn)程的偽并發(fā)。在《現(xiàn)在操作系統(tǒng)》中將這種進(jìn)程間的切換稱之為“多道程序設(shè)計”。
(注:每個進(jìn)程在執(zhí)行過程中表現(xiàn)了不同的形態(tài),CPU需要根據(jù)進(jìn)程執(zhí)行過程中的特性制定CPU調(diào)度算法從而提高CPU利用率)
進(jìn)程切換:由于每個進(jìn)程的處理任務(wù)異樣性,其進(jìn)程的輸入、輸出、處理過程、處理狀態(tài)的都不同,那在進(jìn)程切換的過程中是否也應(yīng)該考慮這些參數(shù)呢?答案是肯定的。一個正在執(zhí)行的進(jìn)程包括程序計數(shù)器、寄存器、變量的當(dāng)前值等,而這些數(shù)據(jù)都是保存在CPU的寄存器中的,且這些寄存器只能是正在使用CPU的進(jìn)程才能享用,所以在進(jìn)程切換時,首先得保存上一個進(jìn)程的這些數(shù)據(jù)(便于下次獲得CPU的使用權(quán)時從上次的中斷處開始繼續(xù)順序執(zhí)行,而不是返回到進(jìn)程開始,否則每次進(jìn)程重新獲得CPU時所處理的任務(wù)都是上一次的重復(fù),可能永遠(yuǎn)也到不了進(jìn)程的結(jié)束出,因為一個進(jìn)程幾乎不可能執(zhí)行完所有任務(wù)后才釋放CPU),然后將本次獲得CPU的進(jìn)程的這些數(shù)據(jù)裝入CPU的寄存器從上次斷點處繼續(xù)執(zhí)行剩下的任務(wù)。操作系統(tǒng)為了便于管理系統(tǒng)內(nèi)部進(jìn)程,為每個進(jìn)程創(chuàng)建了一張進(jìn)程表項,如表1所示。
?。ㄗⅲ篊PU的并發(fā)需求產(chǎn)生了進(jìn)程,進(jìn)程執(zhí)行過程中的特性產(chǎn)生了CPU調(diào)度算法,CPU調(diào)度時需要維護(hù)每個進(jìn)程特有的數(shù)據(jù)和空間,因此產(chǎn)生了維護(hù)每個進(jìn)程的進(jìn)程表項)
多道程序設(shè)計的基本知識回顧差不多了,下慢我們來探討下多道程序設(shè)計模型。
從上面的分析可以得知,多道程序設(shè)計可以提高cpu的利用率。但嚴(yán)格來講,如果進(jìn)程的計算平均時間是進(jìn)程在內(nèi)存中停留時間的20%,且內(nèi)存中同時有5個進(jìn)程,則CPU將一直處于滿負(fù)荷狀態(tài),然而在模擬在實際中過于樂觀,因為其假設(shè)這5個進(jìn)程不會同時等待IO。
下面我們從概率的角度分析CPU的利用率,假設(shè)進(jìn)程等待IO操作的時間與其停留內(nèi)存的時間比例為p,當(dāng)內(nèi)存有n個進(jìn)程時,則n個進(jìn)程同時等待IO的概率為pn。則CPU的利用率為:
CPU的利用率 = 1 - pn
圖1以n為變量的函數(shù)表示了CPU的利用率,n為多道程序設(shè)計的道數(shù)。
從圖中可以看出當(dāng)進(jìn)程花80%進(jìn)行IO時(IO密集型),需要大約10個進(jìn)程并發(fā)才能使CPU得到充分利用;而當(dāng)進(jìn)程只花20%的時間進(jìn)行IO時(稱CPU密集型),孩子需要2個進(jìn)程就可以使CPU的浪費率低于10%。在實際的應(yīng)用中,不管一個等待用戶從終端輸入的交互式進(jìn)程還是做大量讀寫磁盤的服務(wù)器進(jìn)程80%甚至更多的IO時間是普遍的,所以通過多道程序設(shè)計模式可以提高IO密集型進(jìn)程的CPU利用率,從而間接提高了整個系統(tǒng)的吞吐量;而對于CPU密集型進(jìn)程,其并發(fā)度與CPU利用率不一定是成真比例。這套標(biāo)準(zhǔn)體系對與多線程同樣適用,我們稍后進(jìn)一步分析。
多道程序設(shè)計就回顧到這里,可見其核心就是通過進(jìn)程調(diào)度提高CPU的利用率,將一個CPU虛擬成多個,實現(xiàn)多個進(jìn)程的并發(fā)執(zhí)行,至于進(jìn)程如何創(chuàng)建、銷毀、以及狀態(tài)和狀態(tài)轉(zhuǎn)換、進(jìn)程的層次結(jié)構(gòu)以及進(jìn)程的實現(xiàn),此處就不闡述了,如果答不上或者不能隨手捻來的話,還是回去看看《現(xiàn)代操作系統(tǒng)》這本書吧。
(注:進(jìn)程可以分為I/O密集型和CPU密集型,根據(jù)進(jìn)程的不同特性設(shè)置進(jìn)程的策略,來提高CPU利用率,方法不是一成不變的)
下面我們就一起談?wù)劸€程的相關(guān)知識以及與進(jìn)程的關(guān)系。當(dāng)你讀到這里,有的同鞋肯定會問,既然多道程序設(shè)計可以提高CPU的利用率,并實現(xiàn)多個進(jìn)程的并發(fā)執(zhí)行。如果你在提這個問題,表示你在思考,如果你還沒有意識到這個問題,建議你停下結(jié)合之前學(xué)習(xí)的知識先想一想,看看是否自己能給出一個答案?
線程
我們先看看維基百科對線程的定義:線程(英語:thread)是操作系統(tǒng)能夠進(jìn)行運算調(diào)度的最小單位。它被包含在進(jìn)程之中,是行程中的實際運作單位。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以並行多個線程,每條線程并行執(zhí)行不同的任務(wù)。在Unix System V及SunOS中也被稱為輕量進(jìn)程(lightweight processes),但輕量進(jìn)程更多指內(nèi)核線程(kernel thread),而把用戶線程(user thread)稱為線程。此外,從資源分配的角度看,進(jìn)程是資源所有資源分配的基本單位,線程則是CPU調(diào)度的基本單位,即使在單線程進(jìn)程中也是如此。
引入線程的原因:
1) 一個應(yīng)用程序中同時存在多個任務(wù),其中的部分活動會隨時間的推移而阻塞,而另外一部分則不會,例如,一個文字處理軟件,前臺部分需要從終端設(shè)備獲得輸入或者將處理完的部分輸出,而后臺線程則可以實現(xiàn)對文字的處理。故對于CPU密集型進(jìn)程,該用多線程其性能不一定能得到很大提高,但對于IO密集型進(jìn)程,其性能可得到很大提高。
2) 線程比進(jìn)程更輕量級,創(chuàng)建和撤銷的代價小,在許多系統(tǒng)中,創(chuàng)建一個線程比一個進(jìn)程要快10~100倍不等。
3) 在多核CPU中,真正的并行有了可能。即在多線程設(shè)計中一部分可用來處理前臺任務(wù),一部分可用來處理后臺任務(wù),實現(xiàn)真正意義上的并行。
4) 線程間的切換代價要比進(jìn)程切換的代價小。
引入多線程的原因:
1)某個操作可能會陷入長時間等待,等待的線程會進(jìn)入睡眠狀態(tài),無法繼續(xù)執(zhí)行。多線程執(zhí)行可以有效利用等待時間。如等待網(wǎng)絡(luò)響應(yīng)可能需要幾秒的時間。
2)某個操作(常常是計算)會消耗大量的時間,如果只有一個線程,程序和用戶之間的交互會中斷。多線程可以讓一個線程負(fù)責(zé)交付,另一個線程負(fù)責(zé)計算。
3)多CPU或者多核計算機(jī),本身具備同時執(zhí)行多個線程的能力,故單線程無法完全發(fā)揮計算機(jī)的計算能力。
4)相對于多進(jìn)程應(yīng)用,多線程在數(shù)據(jù)共享方面效率要高很多。
5)程序邏輯本身就要求并發(fā)操作。
現(xiàn)在我們通過考察一個例子,就可以更清楚看出多線程的有益之處了。
假設(shè)用戶正在編輯一本書。對于編輯這來說,最容易的辦法是把正本書作為一個文件,便于編輯;而對于計算機(jī)來說把每個章節(jié)作為一個文件處理起來更快,但對于編輯者來說修改就太麻煩了,因為有的修改不止設(shè)計一個章節(jié)而是整本書,例如在整本書中替換某個詞或字等等,如果整本書作為一個文件,正樣處理就方便多了。否則,就得對每個章節(jié)所在文件進(jìn)行處理。
現(xiàn)在如果用在一個1000頁的文檔中刪除第一頁的某一行的某個詞,為保證格式的正確性,字處理軟件需要對文檔進(jìn)行格式處理。但此時用戶需要立刻跳到地800也進(jìn)行另外一處修改,于是字處理軟件被強制對整個書的前800頁進(jìn)程格式處理,因為在排列該頁前面的所有頁面之前,字處理軟件并不知道第800頁的第一行應(yīng)該在哪里。而在第800也的頁面可以顯示在屏幕之前,計算機(jī)可能要拖延想當(dāng)長一段時間進(jìn)行處理,從而令用戶不甚滿意。
此時,多線程便可以有用武之地了。假設(shè)字處理軟件編寫成含有兩個線程的程序。一個線程處理用戶的交互,另一個用來在后臺進(jìn)行格式處理。一旦第一頁發(fā)生的修改,交互線程就立即同時后臺格式處理線程重現(xiàn)整理整本書的格式。同時,交互式線程繼續(xù)監(jiān)控用戶的鼠標(biāo)、鍵盤,并響應(yīng)諸如第一頁之類的簡單命令,此刻,后臺線程正在進(jìn)行瘋狂的運算,如果運氣好的話,格式整理可能在用戶請求查看第800頁之前完成,這樣用戶就感覺不到延遲了。
同理,為保證用戶的編輯工作得到及時保存,可以在添加一個現(xiàn)場周期性對文件進(jìn)現(xiàn)場可以處理磁盤備份,而不必干擾其他兩個線程。擁有三個線程的情形如圖2所示。
圖2 三個線程的字處理軟件
試想,如果是單線程的話,那么在進(jìn)行磁盤備份的時,來自鍵盤或者鼠標(biāo)的命令就會被忽略,直至備份完成。有的同鞋會說,可以引入中斷機(jī)制來中止備份操作,相應(yīng)鼠標(biāo)和鍵盤的命令,但其復(fù)雜性可想而知。如果引入三個線程,其設(shè)計就簡單多了,一個線程用于與用戶交互,第二線程在得到地一個線程的通知后在后臺進(jìn)行文檔的格式化處理,第三個線程則周期性將ARM內(nèi)的內(nèi)容被封到磁盤。
此處,很顯然,這里用三個不同的進(jìn)程是不能工作的,因為三個線程都需要在同一個文件上進(jìn)行操作,通過三個線程,由于一個進(jìn)程內(nèi)的所有線程共享公共內(nèi)存,于是便可以在同一文件上進(jìn)行處理。同理,其他的交互式程序也可以采用同樣的設(shè)計方法。
看完這個例子,部分對多道程序設(shè)計比較忠心的同學(xué)可能會問,上述三個線程能協(xié)同完成工作,主要的便利之處在于其共享了進(jìn)程中的公共內(nèi)存空間。同樣,也可以采用進(jìn)程通信的方式來協(xié)同完成工作?答案確實如此,但仔細(xì)思考幾個問題:1、進(jìn)程通信與線程通信的代價孰高孰第?2、進(jìn)程切換和線程切換的代價?3、如何保證三個進(jìn)程所處理內(nèi)容的一致性?而多線程方案中由于都是對同一文檔內(nèi)容進(jìn)行處理,其一致性的保證則簡單很多。如果能準(zhǔn)確解答上述幾個答案,為什么不選擇多道程序設(shè)計方案來完成其上述工作的原因就不攻自破了吧。
線程的內(nèi)容我們回顧差不多了,現(xiàn)在我們來一起看看進(jìn)程與線程的關(guān)系和區(qū)別吧。
進(jìn)程與線程:
進(jìn)程是操作系統(tǒng)的管理單位,而線程則是進(jìn)程的管理單位;一個線程至少包含一個執(zhí)行線程。不管是在單線程還是多線程中,每個線程都有一個程序計數(shù)器(記錄要執(zhí)行的下一條指令),一組寄存器(保存當(dāng)前線程的工作變量),堆棧(記錄執(zhí)行歷史,其中每一幀保存了一個已經(jīng)調(diào)用但為返回的過程)。雖然線程寄生在進(jìn)程中,但與他的進(jìn)程是不同的概念,并且可以分別處理:進(jìn)程是系統(tǒng)分配資源的基本單位,線程時調(diào)度CPU的基本單位。
多線程是對多進(jìn)程的模擬。前者,多個線程共享同一個地址空間和其他資源,后者共享物理內(nèi)存、磁盤、IO等其他資源,故線程被稱為“輕量級進(jìn)程”。多線程在但CPU系統(tǒng)中運行時,線程輪流運行,猶如多道程序設(shè)計,制造線程并行運行的假象。在一個有三個CPU密集型的進(jìn)程中,實際上每個線程在一個CPU上得到的真實CPU速度的三分之一。不過隨著技術(shù)的發(fā)展,目前主流的CPU都已經(jīng)直接硬件支持多線程,并允許線程在幾個納秒級內(nèi)完成切換。后續(xù)會對多進(jìn)程、多線程、以及多核之間的關(guān)系進(jìn)行總結(jié)。
線程間不像進(jìn)程之間那樣存在很大的獨立性,一個進(jìn)程的多個線程共享進(jìn)程內(nèi)部的很多資源,線程間可以互寫對方的堆棧,而不同的進(jìn)程則無法對其他進(jìn)程的地址空間進(jìn)行寫操作。因此,在實現(xiàn)多線程編程中,應(yīng)設(shè)計合理的同步通信機(jī)制,避免數(shù)據(jù)沖突的現(xiàn)象發(fā)生。圖3給出了進(jìn)程、線程的內(nèi)容,其中進(jìn)程的內(nèi)容是該進(jìn)程的所有線程共享的。
評論