并發(fā)編程基礎(chǔ)知識二 線程和進(jìn)程

一抡砂、知乎 線程和進(jìn)程的區(qū)別是什么大咱?

首先來一句概括的總論:進(jìn)程和線程都是一個(gè)時(shí)間段的描述,是CPU工作時(shí)間段的描述注益。

下面細(xì)說背景:CPU+RAM+各種資源(比如顯卡碴巾,光驅(qū),鍵盤聊浅,GPS, 等等外設(shè))構(gòu)成我們的電腦餐抢,但是電腦的運(yùn)行现使,實(shí)際就是CPU和相關(guān)寄存器以及RAM之間的事情。

一個(gè)最最基礎(chǔ)的事實(shí):CPU太快旷痕,太快碳锈,太快了,寄存器僅僅能夠追的上他的腳步欺抗,RAM和別的掛在各總線上的設(shè)備完全是望其項(xiàng)背售碳。那當(dāng)多個(gè)任務(wù)要執(zhí)行的時(shí)候怎么辦呢?輪流著來?或者誰優(yōu)先級高誰來绞呈?不管怎么樣的策略贸人,一句話就是在CPU看來就是輪流著來。

一個(gè)必須知道的事實(shí):執(zhí)行一段程序代碼佃声,實(shí)現(xiàn)一個(gè)功能的過程介紹 艺智,當(dāng)?shù)玫紺PU的時(shí)候,相關(guān)的資源必須也已經(jīng)就位圾亏,就是顯卡啊十拣,GPS啊什么的必須就位,然后CPU開始執(zhí)行志鹃。這里除了CPU以外所有的就構(gòu)成了這個(gè)程序的執(zhí)行環(huán)境夭问,也就是我們所定義的程序上下文。

當(dāng)這個(gè)程序執(zhí)行完了曹铃,或者分配給他的CPU執(zhí)行時(shí)間用完了缰趋,那它就要被切換出去,等待下一次CPU的臨幸陕见。在被切換出去的最后一步工作就是保存程序上下文秘血,因?yàn)檫@個(gè)是下次他被CPU臨幸的運(yùn)行環(huán)境,必須保存淳玩。

串聯(lián)起來的事實(shí):前面講過在CPU看來所有的任務(wù)都是一個(gè)一個(gè)的輪流執(zhí)行的直撤,具體的輪流方法就是:先加載程序A的上下文,然后開始執(zhí)行A蜕着,保存程序A的上下文谋竖,調(diào)入下一個(gè)要執(zhí)行的程序B的程序上下文,然后開始執(zhí)行B,保存程序B的上下文承匣。蓖乘。。韧骗。

========= 重要的東西出現(xiàn)了========

進(jìn)程和線程就是這樣的背景出來的嘉抒,兩個(gè)名詞不過是對應(yīng)的CPU時(shí)間段的描述,名詞就是這樣的功能袍暴。

進(jìn)程就是包換上下文切換的程序執(zhí)行時(shí)間總和 = CPU加載上下文+CPU執(zhí)行+CPU保存上下文

線程是什么呢些侍?進(jìn)程的顆粒度太大隶症,每次都要有上下的調(diào)入,保存岗宣,調(diào)出蚂会。如果我們把進(jìn)程比喻為一個(gè)運(yùn)行在電腦上的軟件,那么一個(gè)軟件的執(zhí)行不可能是一條邏輯執(zhí)行的耗式,必定有多個(gè)分支和多個(gè)程序段胁住,就好比要實(shí)現(xiàn)程序A,實(shí)際分成 a刊咳,b彪见,c等多個(gè)塊組合而成。那么這里具體的執(zhí)行就可能變成:程序A得到CPU =》CPU加載上下文娱挨,開始執(zhí)行程序A的a小段余指,然后執(zhí)行A的b小段,然后再執(zhí)行A的c小段让蕾,最后CPU保存A的上下文浪规。這里a,b探孝,c的執(zhí)行是共享了A的上下文,CPU在執(zhí)行的時(shí)候沒有進(jìn)行上下文切換的誉裆。這里的a顿颅,b,c就是線程足丢,也就是說線程是共享了進(jìn)程的上下文環(huán)境粱腻,的更為細(xì)小的CPU時(shí)間段。

到此全文結(jié)束斩跌,再一個(gè)總結(jié):進(jìn)程和線程都是一個(gè)時(shí)間段的描述绍些,是CPU工作時(shí)間段的描述,不過是顆粒大小不同耀鸦。

二柬批、阮一峰 進(jìn)程與線程的一個(gè)簡單解釋

進(jìn)程就好比工廠的車間,它代表CPU所能處理的單個(gè)任務(wù)袖订。任一時(shí)刻氮帐,CPU總是運(yùn)行一個(gè)進(jìn)程,其他進(jìn)程處于非運(yùn)行狀態(tài)洛姑。

一個(gè)車間里上沐,可以有很多工人。他們協(xié)同完成一個(gè)任務(wù)楞艾。線程就好比車間里的工人参咙。一個(gè)進(jìn)程可以包括多個(gè)線程龄广。車間的空間是工人們共享的,比如許多房間是每個(gè)工人都可以進(jìn)出的蕴侧。這象征一個(gè)進(jìn)程的內(nèi)存空間是共享的蜀细,每個(gè)線程都可以使用這些共享內(nèi)存。

可是戈盈,每間房間的大小不同奠衔,有些房間最多只能容納一個(gè)人,比如廁所塘娶。里面有人的時(shí)候归斤,其他人就不能進(jìn)去了。這代表一個(gè)線程使用某些共享內(nèi)存時(shí)刁岸,其他線程必須等它結(jié)束脏里,才能使用這一塊內(nèi)存。一個(gè)防止他人進(jìn)入的簡單方法虹曙,就是門口加一把鎖迫横。先到的人鎖上門,后到的人看到上鎖酝碳,就在門口排隊(duì)矾踱,等鎖打開再進(jìn)去。這就叫"互斥鎖"(Mutual exclusion疏哗,縮寫 Mutex)呛讲,防止多個(gè)線程同時(shí)讀寫某一塊內(nèi)存區(qū)域。

還有些房間返奉,可以同時(shí)容納n個(gè)人贝搁,比如廚房。也就是說芽偏,如果人數(shù)大于n雷逆,多出來的人只能在外面等著。這好比某些內(nèi)存區(qū)域污尉,只能供給固定數(shù)目的線程使用膀哲。這時(shí)的解決方法,就是在門口掛n把鑰匙十厢。進(jìn)去的人就取一把鑰匙等太,出來時(shí)再把鑰匙掛回原處。后到的人發(fā)現(xiàn)鑰匙架空了蛮放,就知道必須在門口排隊(duì)等著了缩抡。這種做法叫做"信號量"(Semaphore),用來保證多個(gè)線程不會(huì)互相沖突。

不難看出瞻想,mutex是semaphore的一種特殊情況(n=1時(shí))压真。也就是說,完全可以用后者替代前者蘑险。但是滴肿,因?yàn)閙utex較為簡單,且效率高佃迄,所以在必須保證資源獨(dú)占的情況下泼差,還是采用這種設(shè)計(jì)。

關(guān)于鎖呵俏,可以參考面試必備之樂觀鎖與悲觀鎖堆缘。

(1)悲觀鎖
總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改普碎,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖吼肥,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)阻塞直到它拿到鎖(共享資源每次只給一個(gè)線程使用,其它線程阻塞麻车,用完后再把資源轉(zhuǎn)讓給其它線程)缀皱。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機(jī)制,比如行鎖动猬,表鎖等啤斗,讀鎖,寫鎖等枣察,都是在做操作之前先上鎖争占。Java中synchronized和ReentrantLock等獨(dú)占鎖就是悲觀鎖思想的實(shí)現(xiàn)。

(2)樂觀鎖
總是假設(shè)最好的情況序目,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖伯襟,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù)猿涨,可以使用版本號機(jī)制和CAS算法實(shí)現(xiàn)。樂觀鎖適用于多讀的應(yīng)用類型姆怪,這樣可以提高吞吐量叛赚,像數(shù)據(jù)庫提供的類似于write_condition機(jī)制,其實(shí)都是提供的樂觀鎖稽揭。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實(shí)現(xiàn)方式CAS實(shí)現(xiàn)的俺附。

(3)兩種鎖的使用場景
從上面對兩種鎖的介紹,我們知道兩種鎖各有優(yōu)缺點(diǎn)溪掀,不可認(rèn)為一種好于另一種事镣,像樂觀鎖適用于寫比較少的情況下(多讀場景),即沖突真的很少發(fā)生的時(shí)候揪胃,這樣可以省去了鎖的開銷璃哟,加大了系統(tǒng)的整個(gè)吞吐量氛琢。但如果是多寫的情況,一般會(huì)經(jīng)常產(chǎn)生沖突随闪,這就會(huì)導(dǎo)致上層應(yīng)用會(huì)不斷的進(jìn)行retry阳似,這樣反倒是降低了性能,所以一般多寫的場景下用悲觀鎖就比較合適铐伴。

三撮奏、單核多線程

參考對于單核cpu而言,開多線程的目的難倒只能是為了防止阻塞么当宴?

以下是一些單核cpu多線程的疑問畜吊,求解答(都指單核)。
1.如果一個(gè)進(jìn)程有n個(gè)任務(wù)要處理即供,因?yàn)榻K究是在一個(gè)cpu上跑定拟,所以這n個(gè)任務(wù)在一個(gè)線程還是多個(gè)線程上跑,執(zhí)行的總時(shí)間是一樣的(多線程逗嫡,線程切換可能更浪費(fèi)時(shí)間)青自?
2.是否進(jìn)程開多線程就能搶到更多的cpu時(shí)間,python這種帶GIL的估計(jì)是沒戲了驱证,那么java呢延窜?
3.自己搶到更多cpu,機(jī)器上的其它程序不就cpu時(shí)間少了么抹锄?是因?yàn)閏pu大部分時(shí)間都是空閑的逆瑞,不怕?lián)尨壳鳎窟€是因?yàn)樵谧鰬?yīng)用層開發(fā)的時(shí)候流椒,是不用考慮其它程序能不能搶到cpu時(shí)間的凉倚。
4.一個(gè)進(jìn)程所有線程能搶到的時(shí)間片總和是有最大值嗎卦睹?一個(gè)線程一次能拿到多長的cpu時(shí)間疗我?
綜上袖迎,我的最大疑問就是:對于單核cpu而言鸽心,開多線程難倒只能防止阻塞么聊闯?

(以下回答均針對單核CPU)

問題1概括下來就是很多人喜歡爭論的多線程究竟能不能提高性能布疼?首先摊趾,回答是“能或者不能”。至于“不能”你已經(jīng)理解了游两,那么我來說說為什么多線程“能”提高性能砾层。要知道一個(gè)作業(yè)可不總是CPU密集型的,必然穿插著大量的IO調(diào)用在其中贱案。而IO的一個(gè)特性就是阻塞等待肛炮。這個(gè)阻塞等待的時(shí)間消耗往往是遠(yuǎn)遠(yuǎn)大于線程切換所消耗的時(shí)間的,如果你要訪問10個(gè)url獲取接口內(nèi)容,假如一次http訪問平均阻塞時(shí)間大概是1s铸董,那么你是一個(gè)一個(gè)的線性訪問快還是10個(gè)線程訪問快祟印?相信不用算也知道多線程肯定更快。最后就可以得出結(jié)論粟害,多線程在CPU密集型的作業(yè)下的確不能提高性能甚至更浪費(fèi)時(shí)間蕴忆,但是在IO密集型的作業(yè)下則可以提升性能(或者更準(zhǔn)確點(diǎn)說叫平均響應(yīng)時(shí)間)。

問題2悲幅,進(jìn)程是最小作業(yè)單元套鹅,跟進(jìn)程內(nèi)開多少線程都無關(guān),CPU對進(jìn)程的調(diào)度是統(tǒng)一的汰具。所以多線程無法促進(jìn)進(jìn)程被CPU青睞卓鹿。python的GIL也是只在CPU密集型的作業(yè)下顯現(xiàn)的,通常的業(yè)務(wù)充斥著大量的IO留荔,所以如果你不是做科學(xué)計(jì)算吟孙,那么放心大膽的使用多線程吧。

問題3聚蝶,4杰妓,雖說操作系統(tǒng)有自己的調(diào)度策略,比如爭搶碘勉,時(shí)間片輪轉(zhuǎn)巷挥,但是用戶態(tài)進(jìn)程僅僅想通過自身應(yīng)用級的代碼實(shí)現(xiàn)如多線程等手段企圖加大自身的CPU調(diào)度權(quán)重是不行的,不過自身的線程是可以實(shí)現(xiàn)優(yōu)先級設(shè)置的验靡。也就是說CPU給你整個(gè)進(jìn)程的資源是有限且無法更改的倍宾,但是這些資源如何分配你是可以參與的,比如設(shè)置線程的優(yōu)先級胜嗓,也只是參與不能主導(dǎo)CPU在某個(gè)線程的調(diào)度時(shí)間高职,這個(gè)是無法控制的。跟當(dāng)時(shí)的系統(tǒng)壓力有關(guān)辞州。

綜上初厚,你的問題提到了“阻塞”,這是服務(wù)端編程永恒的經(jīng)典話題孙技。不管是多進(jìn)程,多線程排作,還是協(xié)程牵啦,大多都是致力于解決IO問題,說白了都是怎么樣把阻塞變成非阻塞的手段妄痪。

四哈雏、多核情況

線程進(jìn)程是怎樣使用多核的中,作者做了一個(gè)測試:多核時(shí),一個(gè)線程是始終由一個(gè)cpu核運(yùn)行還是每個(gè)cpu核都會(huì)運(yùn)行該線程呢裳瘪?測試結(jié)果是多核cpu情況下土浸,一個(gè)線程不是由某一個(gè)核一直執(zhí)行完成的。

單核多線程與多核多線程中彭羹,單核多線程指的是單核CPU輪流執(zhí)行多個(gè)線程黄伊,通過給每個(gè)線程分配CPU時(shí)間片來實(shí)現(xiàn),只是因?yàn)檫@個(gè)時(shí)間片非常短(幾十毫秒)派殷,所以在用戶角度上感覺是多個(gè)線程同時(shí)執(zhí)行还最。

多核多線程,可以把多線程分配給不同的核心處理毡惜,其他的線程依舊等待拓轻,相當(dāng)于多個(gè)線程并行的在執(zhí)行,而單核多線程只能是并發(fā)经伙。

這里關(guān)于并發(fā)和并行的區(qū)別扶叉,可以參考并發(fā)編程基礎(chǔ)知識一 并發(fā)和并行

五、多線程有什么用帕膜?

這么解釋問題吧:
1枣氧。單進(jìn)程單線程:一個(gè)人在一個(gè)桌子上吃菜。
2泳叠。單進(jìn)程多線程:多個(gè)人在同一個(gè)桌子上一起吃菜作瞄。
3。多進(jìn)程單線程:多個(gè)人每個(gè)人在自己的桌子上吃菜危纫。

多線程的問題是多個(gè)人同時(shí)吃一道菜的時(shí)候容易發(fā)生爭搶宗挥,例如兩個(gè)人同時(shí)夾一個(gè)菜,一個(gè)人剛伸出筷子种蝶,結(jié)果伸到的時(shí)候已經(jīng)被夾走菜了契耿。。螃征。此時(shí)就必須等一個(gè)人夾一口之后搪桂,在還給另外一個(gè)人夾菜,也就是說資源共享就會(huì)發(fā)生沖突爭搶盯滚。

1踢械。對于 Windows 系統(tǒng)來說,【開桌子】的開銷很大魄藕,因此 Windows 鼓勵(lì)大家在一個(gè)桌子上吃菜内列。因此 Windows 多線程學(xué)習(xí)重點(diǎn)是要大量面對資源爭搶與同步方面的問題。

2背率。對于 Linux 系統(tǒng)來說话瞧,【開桌子】的開銷很小嫩与,因此 Linux 鼓勵(lì)大家盡量每個(gè)人都開自己的桌子吃菜。這帶來新的問題是:坐在兩張不同的桌子上交排,說話不方便划滋。因此,Linux 下的學(xué)習(xí)重點(diǎn)大家要學(xué)習(xí)進(jìn)程間通訊的方法埃篓。

關(guān)于開銷处坪,知乎原回答有更多展開。也可以參考多線程還是多進(jìn)程的選擇及區(qū)別

六都许、java多線程 synchronized節(jié)選一部分作簡介
  • jvm的可見性:當(dāng)一個(gè)共享變量在多個(gè)線程工作內(nèi)存中都存在副本時(shí)稻薇,如果一個(gè)線程修改了這個(gè)共享變量,其他線程能夠看到這個(gè)修改后的值胶征,即可見性塞椎。
  • jvm的有序性:假如有個(gè)共享變量x=10,線程a執(zhí)行x=x+1睛低,線程b執(zhí)行x=x-1案狠。
a的執(zhí)行順序:
1 從主存中讀取變量x副本到工作內(nèi)存
2 給x加1
3 將x加1后的值寫回主 存
b的執(zhí)行順序:
1 從主存中讀取變量x副本到工作內(nèi)存
2 給x減1
3 將x減1后的值寫回主存
實(shí)際上順序有可能是這樣的:
1:線程a從主存讀取x副本到工作內(nèi)存,工作內(nèi)存中x值為10
2:線程b從主存讀取x副本到工作內(nèi)存钱雷,工作內(nèi)存中x值為10
3:線程a將工作內(nèi)存中x加1骂铁,工作內(nèi)存中x值為11
4:線程a將x提交主存中,主存中x為11
5:線程b將工作內(nèi)存中x值減1罩抗,工作內(nèi)存中x值為9
6:線程b將x提交到中主存中拉庵,主存中x為9

synchronized關(guān)鍵字可以保障一個(gè)線程計(jì)算時(shí),共享變量處于上鎖狀態(tài):

1 獲得同步鎖
2 清空工作內(nèi)存
3 從主存拷貝變量副本到工作內(nèi)存
4 對這些變量計(jì)算
5 將變量從工作內(nèi)存寫回到主存
6 釋放鎖

volatile關(guān)鍵字套蒂,開銷比synchronized要小钞支,但是它只能保證可見性,無法保證有序性操刀。volatile會(huì)直接操作主存烁挟,沒有線程對工作內(nèi)存和主存同步。比較適合直接給共享變量賦值這種操作骨坑。

七撼嗓、優(yōu)化

1.大多數(shù)游戲做多核優(yōu)化的難點(diǎn)是什么?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末欢唾,一起剝皮案震驚了整個(gè)濱河市且警,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁遣,老刑警劉巖振湾,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亡脸,居然都是意外死亡押搪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門浅碾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來大州,“玉大人,你說我怎么就攤上這事垂谢∠没” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵滥朱,是天一觀的道長根暑。 經(jīng)常有香客問我,道長徙邻,這世上最難降的妖魔是什么排嫌? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮缰犁,結(jié)果婚禮上淳地,老公的妹妹穿的比我還像新娘。我一直安慰自己帅容,他們只是感情好颇象,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著并徘,像睡著了一般遣钳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麦乞,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天蕴茴,我揣著相機(jī)與錄音,去河邊找鬼路幸。 笑死荐开,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的简肴。 我是一名探鬼主播晃听,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼砰识!你這毒婦竟也來了能扒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤辫狼,失蹤者是張志新(化名)和其女友劉穎初斑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膨处,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡见秤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年砂竖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹃答。...
    茶點(diǎn)故事閱讀 40,561評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乎澄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出测摔,到底是詐尸還是另有隱情置济,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布锋八,位于F島的核電站浙于,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏挟纱。R本人自食惡果不足惜羞酗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望樊销。 院中可真熱鬧整慎,春花似錦、人聲如沸围苫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剂府。三九已至拧揽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腺占,已是汗流浹背淤袜。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衰伯,地道東北人铡羡。 一個(gè)月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像意鲸,于是被迫代替她去往敵國和親烦周。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容