資源描述:
《淺談多核cpu、多線程與并行計(jì)算》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在行業(yè)資料-天天文庫(kù)。
1、0.前言最近發(fā)覺自己博客轉(zhuǎn)帖的太多,于是決定自己寫一個(gè)原創(chuàng)的。筆者用過MPI和C#線程池,參加過比賽,有所感受,將近一年來,對(duì)多線程編程興趣一直不減,一直有所關(guān)注,決定寫篇文章,算是對(duì)知識(shí)的總結(jié)吧。有說的不對(duì)的地方,歡迎各位大哥們指正:)1.CPU發(fā)展趨勢(shì)核心數(shù)目依舊會(huì)越來越多,依據(jù)摩爾定律,由于單個(gè)核心性能提升有著嚴(yán)重的瓶頸問題,普通的桌面PC有望在2017年末2018年初達(dá)到24核心(或者16核32線程),我們?nèi)绾蝸砻鎸?duì)這突如其來的核心數(shù)目的增加?編程也要與時(shí)俱進(jìn)。筆者斗膽預(yù)測(cè),CPU各個(gè)核心之間的片內(nèi)總線將會(huì)采用4路組相連:),因?yàn)槿噙B太過復(fù)雜,單總線又不夠給力。而且應(yīng)該是非
2、對(duì)稱多核處理器,可能其中會(huì)混雜幾個(gè)DSP處理器或流處理器。2.多線程與并行計(jì)算的區(qū)別(1)多線程的作用不只是用作并行計(jì)算,他還有很多很有益的作用。還在單核時(shí)代,多線程就有很廣泛的應(yīng)用,這時(shí)候多線程大多用于降低阻塞(意思是類似于while(1){if(flag==1)break;sleep(1);}這樣的代碼)帶來的CPU資源閑置,注意這里沒有浪費(fèi)CPU資源,去掉sleep(1)就是純浪費(fèi)了。阻塞在什么時(shí)候發(fā)生呢?一般是等待IO操作(磁盤,數(shù)據(jù)庫(kù),網(wǎng)絡(luò)等等)。此時(shí)如果單線程,CPU會(huì)干轉(zhuǎn)不干實(shí)事(與本程序無關(guān)的事情都算不干實(shí)事,因?yàn)閳?zhí)行其他程序?qū)ξ襾碚f沒意義),效率低下(針對(duì)這個(gè)程序而
3、言),例如一個(gè)IO操作要耗時(shí)10毫秒,CPU就會(huì)被阻塞接近10毫秒,這是何等的浪費(fèi)?。∫繡PU是數(shù)著納秒過日子的。所以這種耗時(shí)的IO操作就用一個(gè)線程Thread去代為執(zhí)行,創(chuàng)建這個(gè)線程的函數(shù)(代碼)部分不會(huì)被IO操作阻塞,繼續(xù)干這個(gè)程序中其他的事情,而不是干等待(或者去執(zhí)行其他程序)。同樣在這個(gè)單核時(shí)代,多線程的這個(gè)消除阻塞的作用還可以叫做“并發(fā)”,這和并行是有著本質(zhì)的不同的。并發(fā)是“偽并行”,看似并行,而實(shí)際上還是一個(gè)CPU在執(zhí)行一切事物,只是切換的太快,我們沒法察覺罷了。例如基于UI的程序(俗話說就是圖形界面),如果你點(diǎn)一個(gè)按鈕觸發(fā)的事件需要執(zhí)行10秒鐘,那么這個(gè)程序就會(huì)假死
4、,因?yàn)槌绦蛟诿χ鴪?zhí)行,沒空搭理用戶的其他操作;而如果你把這個(gè)按鈕觸發(fā)的函數(shù)賦給一個(gè)線程,然后啟動(dòng)線程去執(zhí)行,那么程序就不會(huì)假死,繼續(xù)相應(yīng)用戶的其他操作。但是,隨之而來的就是線程的互斥和同步、死鎖等問題,詳細(xì)見有關(guān)文獻(xiàn)?,F(xiàn)在是多核時(shí)代了,這種線程的互斥和同步問題是更加嚴(yán)峻的,單核時(shí)代大都算并發(fā),多核時(shí)代真的就大為不同,為什么呢?具體細(xì)節(jié)請(qǐng)參考有關(guān)文獻(xiàn)。我這里簡(jiǎn)單解釋一下,以前volatile型變量的使用可以解決大部分問題,例如多個(gè)線程共同訪問一個(gè)Flag標(biāo)志位,如果是單核并發(fā),基本不會(huì)出問題(P.S.在什么情況下會(huì)出問題呢?Flag有多個(gè),或者是一個(gè)數(shù)組,這時(shí)候只能通過邏輯手段搞定這個(gè)
5、問題了,多來幾次空轉(zhuǎn)無所謂,別出致命問題就行),因?yàn)镃PU只有一個(gè),同時(shí)訪問這個(gè)標(biāo)志位的只能有一個(gè)線程,而多核情況下就不太一樣了,所以僅僅volatile不太能解決問題,這就要用到具體語(yǔ)言,具體環(huán)境中的“信號(hào)量”了,Mutex,Monitor,Lock等等,這些類都操作了硬件上的“關(guān)中斷”,達(dá)到“原語(yǔ)”效果,對(duì)臨界區(qū)的訪問不被打斷的效果,具體就不解釋了,讀者可以看看《現(xiàn)代操作系統(tǒng)》。(2)并行計(jì)算還可以通過其他手段來獲得,而多線程只是其中之一。其他手段包括:多進(jìn)程(這又包括共享存儲(chǔ)區(qū)的和分布式多機(jī),以及混合式的),指令級(jí)并行。ILP(指令級(jí)并行),x86架構(gòu)里叫SMT(同時(shí)多線程),
6、在MIPS架構(gòu)里與之對(duì)應(yīng)的是superscalar(超標(biāo)量)和亂序執(zhí)行,二者有區(qū)別,但共同點(diǎn)都是可以達(dá)到指令級(jí)并行,這是用戶沒法控制的,不屬于編程范圍,只能做些有限的優(yōu)化,而這有限的優(yōu)化可能只屬于編譯器管轄的范疇,用戶能做的甚少。(3)典型的適于并行計(jì)算的語(yǔ)言Erlang和MPI:這兩個(gè)前者是語(yǔ)言,后者是C++和Fortran的擴(kuò)展庫(kù),效果是一樣的,利用多進(jìn)程實(shí)現(xiàn)并行計(jì)算,Erlang是共享存儲(chǔ)區(qū)的,MPI是混合型的。C#.NET4.0:新版本4.0可以用少量代碼實(shí)現(xiàn)并行For循環(huán),之前版本需要用很繁瑣的代碼才能實(shí)現(xiàn)同樣功能。這是利用了多線程實(shí)現(xiàn)并行計(jì)算。Java和C#3.5都有線程
7、池(ThreadPool),也是不錯(cuò)的很好用的多線程管理類,可以方便高效的使用多線程。CUDA,還是個(gè)初生牛犢,有很大的發(fā)展?jié)摿Γ徊贿^就目前其應(yīng)用領(lǐng)域很有限。其目前只能使用C語(yǔ)言,而且還不是C99,比較低級(jí),不能使用函數(shù)指針。個(gè)人感覺這由于硬件上天生的局限性(平均每個(gè)核心可用內(nèi)存小,與系統(tǒng)內(nèi)存通訊時(shí)間長(zhǎng)),只適用于做科學(xué)計(jì)算,靜態(tài)圖像處理,視頻編碼解碼,其他領(lǐng)域,還不如高端CPU。等以后GPU有操作系統(tǒng)了,能充分調(diào)度GPU資源了,GPU就可以當(dāng)大神了。游