并發(fā)不等于并行_第1頁
并發(fā)不等于并行_第2頁
并發(fā)不等于并行_第3頁
并發(fā)不等于并行_第4頁
并發(fā)不等于并行_第5頁
已閱讀5頁,還剩58頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

并發(fā)(Concurrency)

!=并行(Parallelism)郭紅俊2014-01-24為什么要講這個主題今天的情況(硬件):多核海量移動設(shè)備網(wǎng)絡(luò)(移動網(wǎng)絡(luò))、io瓶頸如何解決?線程和事件(同步和異步)之爭,c10k問題多線程+內(nèi)存共享(用線程處理并發(fā))一個客戶端1個線程多線程同步有太多細(xì)節(jié)要考慮;線程不夠輕量,占用資源高,切換負(fù)擔(dān)大;事件驅(qū)動模型(用事件處理并發(fā))一個線程多個客戶端nonblockingI/O或者asynchronousI/Onginx,Tornado,node.js編程復(fù)雜類似Actor/CSP的消息傳遞機(jī)制電信系統(tǒng)中的erlang(用一些并發(fā)的實(shí)體,稱為actor,他們之間的通過發(fā)送消息來同步)GolangGolang提供的并發(fā)功能并發(fā)執(zhí)行(輕量級線程)concurrentexecution(goroutines)同步和消息傳遞synchronizationandmessaging(channels)多路并發(fā)控制multi-wayconcurrentcontrol(select)協(xié)程和通道的關(guān)系協(xié)程負(fù)責(zé)執(zhí)行代碼,通道負(fù)責(zé)在協(xié)程之間傳遞事件通道是協(xié)程之間的數(shù)據(jù)傳輸通道。通道可以在眾多的協(xié)程之間傳遞數(shù)據(jù),具體可以值也可以是個引用。通道有兩種使用方式。協(xié)程可以試圖向通道放入數(shù)據(jù),如果通道滿了,會掛起協(xié)程,直到通道可以為他放入數(shù)據(jù)為止。協(xié)程可以試圖向通道索取數(shù)據(jù),如果通道沒有數(shù)據(jù),會掛起協(xié)程,直到通道返回數(shù)據(jù)為止。如此,通道就可以在傳遞數(shù)據(jù)的同時,控制協(xié)程的運(yùn)行。有點(diǎn)像事件驅(qū)動,也有點(diǎn)像阻塞隊列。CSP模式(并發(fā)+通信)并發(fā)是一種將一個程序分解成小片段獨(dú)立執(zhí)行的程序設(shè)計方法。

通信是指各個獨(dú)立的執(zhí)行任務(wù)間的合作。

這是Go語言采用的模式,包括Erlang等其它語言都是基于這種CSP模式:

C.A.R.Hoare:CommunicatingSequentialProcesses(CACM1978)CSP(“通過通信來共享內(nèi)存,而非通過共享內(nèi)存來通信”的原則)并發(fā)與并行并發(fā)真酷!耶,并行了?。〔?,錯了。當(dāng)Go語言發(fā)布時,很多人區(qū)分不了這兩者之間的差別。"我用4個處理器來執(zhí)行素數(shù)篩選程序,但程序執(zhí)行的更慢了!并發(fā)Concurrency將相互獨(dú)立的執(zhí)行過程綜合到一起的編程技術(shù)。

(這里是指通常意義上的執(zhí)行過程,而不是Linux進(jìn)程。)|<

<

9

>

>|

分享

?9

并發(fā)真酷!耶,并行了??!不!錯了。

當(dāng)Go語言發(fā)布時,很多人區(qū)分不了這兩者之間的差別。

"我用4個處理器來執(zhí)行素數(shù)篩選程序,但程序執(zhí)行的更慢了!"

并發(fā)Concurrency將相互獨(dú)立的執(zhí)行過程綜合到一起的編程技術(shù)。

(這里是指通常意義上的執(zhí)行過程,而不是Linux進(jìn)程。很難定義。)

并行Parallelism同時執(zhí)行(通常是相關(guān)的)計算任務(wù)的編程技術(shù)。并發(fā)vs.并行并發(fā)是指同時處理很多事情。

而并行是指同時能完成很多事情。

兩者不同,但相關(guān)。

一個重點(diǎn)是組合,一個重點(diǎn)是執(zhí)行。

并發(fā)提供了一種方式讓我們能夠設(shè)計一種方案將問題(非必須的)并行的解決。并發(fā)和并行,關(guān)鍵在于關(guān)注點(diǎn)不同并發(fā)關(guān)注的是資源充分利用(組合);比如你(代表資源)在公司打工,老板為了最大化壓榨你,會給你各種活兒干(代表任務(wù)),讓你別閑下來;這時候你是在并發(fā)工作的,但你不可能同時做兩個活兒,只能一個一個的干(早期的批處理系統(tǒng)),或者把每個活兒分解成一個一個關(guān)聯(lián)度不高的小活兒,交替著干(現(xiàn)代的分時系統(tǒng))并行關(guān)注的是一個任務(wù)被分解給多個執(zhí)行者同時做,縮短這個任務(wù)的完成時間(執(zhí)行);比如你們老板接了個大活兒,把這個大活兒拆分成多個盡量不相干的小活分給多個人干;這里重點(diǎn)是“盡量不相干”,如果老板牛、拆得好,多個人不需要溝通很快就做完了,如果老板爛、拆得差,多個人需要頻繁溝通等待別人,那就會非常慢,有可能比一個人做還慢,這里在員工水平一致的情況下(代表并行需要的資源),老板的水平(并行算法)決定了任務(wù)的快慢。進(jìn)一步,并發(fā)和并行是可以組合的,比如你給多家公司兼職,就相當(dāng)于你在”并發(fā)“的(針對你而言是并發(fā))干活,而你干的活兒是在”并行“著(還有其它人在干)ConcurrencyvsParallelism一個并發(fā)程序是指能同時執(zhí)行通常不相關(guān)的各種任務(wù)。以一個游戲服務(wù)器為例子:它通常是有各種組件組成,每種組件都跟外部世界進(jìn)行著復(fù)雜的信息交互。一個組件有可能要處理多個用戶聊聊;另外一些可能要處理用戶的輸入,并把最新狀態(tài)反饋給用戶;其它的用來進(jìn)行物理計算。這些都是并發(fā)處理。并發(fā)程序并不需要多核處理器。相比之下,并行程序是用來解決一個單一任務(wù)的。以一個試圖預(yù)估某支股票價格在下一分鐘波動情況的金融組件為例,如果想最快速度的知道標(biāo)普500中哪知股票應(yīng)該賣出還是買進(jìn),你不能一個一個的計算,而是將這些所有的股票同時計算。這是并行。并發(fā)和并行的關(guān)系在CMU那本著名的《ComputerSystems:AProgrammer’sPerspective》里的這張圖也非常直觀清晰:并發(fā)(Concurrency)

vs并行(Parallelism)并發(fā)就是一心二用(多用),比如你一邊聽老師講課,一邊低頭看課桌下韓寒的小說。這兩件事你在同時做,而且這兩件事并不一定需要相關(guān)。并行就是兵分幾路干同一個事情。比如別人看小說只能一行一行的看,而你能一目十行,這就是并行。繁忙的地鼠概念太抽象。我們來點(diǎn)具體的。

我們的問題運(yùn)一堆沒用的手冊到焚燒爐里。如果只有一只地鼠,這需要很長時間。更多的地鼠!更多的地鼠還不行;他們需要更多的小推車。更多的地鼠和更多的小推車這樣快多了,但在裝運(yùn)處和焚燒爐處出現(xiàn)了瓶頸。

還有,這些地鼠需要能同時工作。

它們需要相互通知。(這就是地鼠之間的通信)所有東西都增加一倍消除瓶頸;讓他們能真正的相互獨(dú)立不干擾。這樣吞吐速度會快一倍。并發(fā)組合并發(fā)組合兩個地鼠的工作過程?,F(xiàn)在的這種工作流程不能自動的實(shí)現(xiàn)并行!如果只有一只地鼠,這仍然是并發(fā)(就是目前的這種工作方式),但它不是并行。然而,它是可以并行的!需要設(shè)計出另外的工作流程來實(shí)現(xiàn)并發(fā)組合。新的工作流程三只地鼠在工作,但看起來工作有些滯后。

每只地鼠都在做一種獨(dú)立的工序,

并且相互合作(通信)。更細(xì)分工的并發(fā)增加一只地鼠,專門運(yùn)回空的小推車。四只地鼠組成了一個優(yōu)化的工作流程,每只只做自己一種簡單的工序。

如果任務(wù)布置的合理,這將會比最初一個地鼠的工作快4倍。結(jié)果我們通過在現(xiàn)有的工作流程里加入并發(fā)過程從而改進(jìn)了執(zhí)行效率。

地鼠越多能做的越多;工作效率越高。

這是一種比僅僅并行更深刻的認(rèn)識。并發(fā)過程四個地鼠有不同的工作環(huán)節(jié):往小推車?yán)镅b書移動小推車到焚燒爐卸載書到焚燒爐里送回空的小推車不同的并發(fā)設(shè)計能導(dǎo)致不同的并行方式。更多的并行!現(xiàn)在我們可以讓并行再多一倍;按照現(xiàn)在的并行模式很容易實(shí)現(xiàn)這些。八個地鼠,全部繁忙。它們可以完全不并行請記住,只有一個地鼠在工作(零并行),這仍然是一個正確的并發(fā)的工作方案。換一種設(shè)計現(xiàn)在我們換一種設(shè)計來組織我們的地鼠的并發(fā)工作流程。

兩個地鼠,一個中轉(zhuǎn)站。讓常規(guī)的流程并行化更多的并發(fā)流程能獲得更多的吞吐量。另外一種方法在每個中轉(zhuǎn)站之間都引入多個地鼠并發(fā)的模式:全程優(yōu)化使用這種技術(shù)策略,16個地鼠都很繁忙!習(xí)得有很多分解流程的方式。

這都是并發(fā)設(shè)計。

一旦完成了分解,并行可能會喪失,但很容易糾正?;氐接嬎銠C(jī)世界將我們的運(yùn)書工作替換成如下:書堆=>Web內(nèi)容地鼠=>CPU小推車=>調(diào)度,渲染或網(wǎng)絡(luò)傳輸焚燒爐=>代理,瀏覽器或其他消費(fèi)源我們現(xiàn)在的這種設(shè)計就是一種可擴(kuò)展的Web服務(wù)的并發(fā)設(shè)計。

地鼠提供Web內(nèi)容服務(wù)。關(guān)于Go語言的一點(diǎn)背景知識這里不是一個詳細(xì)的教材,只是快速做一些重點(diǎn)介紹。Go協(xié)程(Goroutines)一個Go協(xié)程就是一個和其它Go協(xié)程在同一地址空間里但卻獨(dú)立運(yùn)行的函數(shù)。就像是在shell里使用&標(biāo)記啟動一個命令。f("hello","world")//fruns;wewaitgof("hello","world")

//fstartsrunning

g()

//doesnotwaitforftoreturn

Go協(xié)程不是線程(很像線程,但比線程更輕量。)多個協(xié)程可以在系統(tǒng)線程上做多路通信。當(dāng)一個Go協(xié)程阻塞時,所在的線程會阻塞,但其它Go協(xié)程不受影響。Channels(通道,消息傳遞)通道是類型化的值,能夠被Go例程用來做同步或交互信息。timerChan:=make(chantime.Time)gofunc(){time.Sleep(deltaT)timerChan<-time.Now()//sendtimeontimerChan}()//Dosomethingelse;whenready,receive.//ReceivewillblockuntiltimerChandelivers.//Valuesentisothergoroutine'pletedAt:=<-timerChanSelect(多路并發(fā))這select語句很像switch,但它的判斷條件是基于通信,而不是基于值的等量匹配。select{casev:=<-ch1:fmt.Println("channel1sends",v)casev:=<-ch2:fmt.Println("channel2sends",v)default://optionalfmt.Println("neitherchannelwasready")}Go語言當(dāng)真支持并發(fā)Really。

一個程序里產(chǎn)生成千上萬個Go例程很正常。

(有一次調(diào)試一個程序發(fā)現(xiàn)有130萬個例程。)

堆棧初始很小,但隨著需求會增長或收縮。

Go例程不是不耗資源,但它們很輕量級的。閉包在這里也是重要角色它讓一些并發(fā)運(yùn)算更容易表達(dá)。它們是局部函數(shù)。下面是一個非并發(fā)例子。funcCompose(f,gfunc(xfloat)float)func(xfloat)float{returnfunc(xfloat)float{returnf(g(x))}}print(Compose(sin,cos)(0.5))一些例子通過實(shí)例學(xué)習(xí)Go語言并發(fā)啟動后臺程序使用閉包封裝一個后臺操作。

下面是從輸入通道拷貝數(shù)據(jù)到輸出通道。這個forrange操作會一直執(zhí)行到處理掉通道內(nèi)最后一個值。gofunc(){//copyinputtooutputforval:=rangeinput{output<-val}}()一個簡單的負(fù)載均衡的例子(1)數(shù)據(jù)類型:typeWorkstruct{x,y,zint}一個簡單的負(fù)載均衡的例子(2)一個worker的任務(wù):必須保證當(dāng)一個worker阻塞時其他worker仍能運(yùn)行。funcworker(in<-chan*Work,outchan<-*Work){forw:=rangein{w.z=w.x*w.ySleep(w.z)out<-w}}一個簡單的負(fù)載均衡的例子(3)runner:很簡單的任務(wù),但如果沒有并發(fā)機(jī)制,你仍然很難這么簡單的解決。funcRun(){in,out:=make(chan*Work),make(chan*Work)fori:=0;i<NumWorkers;i++{goworker(in,out)}gosendLotsOfWork(in)receiveLotsOfResults(out)}并發(fā)是并行成為可能這個負(fù)載均衡的例子具有很明顯的并行和可擴(kuò)展性。

Worker數(shù)可以非常巨大。

Go語言的這種并發(fā)特征能的開發(fā)一個安全的、好用的、可擴(kuò)展的、并行的軟件變得很容易。并發(fā)簡化了同步?jīng)]有明顯的需要同步的操作。

程序的這種設(shè)計隱含的實(shí)現(xiàn)了同步。真是太簡單了讓我們實(shí)現(xiàn)一個更有意義的負(fù)載均衡的例子。負(fù)載均衡定義負(fù)載請求請求者向均衡服務(wù)發(fā)送請求。注意這返回的通道是放在請求內(nèi)部的。

通道是first-class值typeRequeststruct{fnfunc()int//Theoperationtoperform.cchanint//Thechanneltoreturntheresult.}負(fù)載產(chǎn)生者沒有實(shí)際用處,但能很好的模擬一個請求者,一個負(fù)載產(chǎn)生者。funcrequester(workchan<-Request){c:=make(chanint)for{//Killsometime(fakeload).Sleep(rand.Int63n(nWorker*2*Second))work<-Request{workFn,c}//sendrequestresult:=<-c//waitforanswerfurtherProcess(result)}}Worker定義一些請求通道,加上一些負(fù)載記錄數(shù)據(jù)。typeWorkerstruct{requestschanRequest//worktodo(bufferedchannel)pendingint

//countofpendingtasksindexint

//indexintheheap}Worker工作流程均衡服務(wù)將請求發(fā)送給壓力最小的worker。每個worker的工作流程如下:請求通道(w.requests)將請求提交給各個worker。均衡服務(wù)跟蹤請求待處理的數(shù)量來判斷負(fù)載情況。

每個響應(yīng)直接反饋給它的請求者。

你可以將循環(huán)體內(nèi)的代碼當(dāng)成Go例程從而實(shí)現(xiàn)并行。func(w*Worker)work(donechan*Worker){for{req:=<-w.requests//getRequestfrombalancerreq.c<-req.fn()//callfnandsendresultdone<-w//we'vefinishedthisrequest}}定義負(fù)載均衡器負(fù)載均衡器需要一個裝很多worker的池子和一個通道來讓請求者報告任務(wù)完成情況。typePool[]*WorkertypeBalancerstruct{poolPooldonechan*Worker}負(fù)載均衡函數(shù)簡單!你只需要實(shí)現(xiàn)dispatch和completed方法。func(b*Balancer)balance(workchanRequest){for{select{casereq:=<-work://receivedaRequest...b.dispatch(req)//...sosendittoaWorkercasew:=<-b.done://aworkerhasfinished...pleted(w)//...soupdateitsinfo}}}儲存通道的堆(heap)負(fù)載均衡的worker池子是一個Heap隊列。

Heap是一個支持優(yōu)先級的隊列typeInterfaceinterface{sort.InterfacePush(xinterface{})//addxaselementLen()Pop()interface{}//removeandreturnelementLen()-1.}儲存通道的堆(heap)將負(fù)載均衡的池子用一個Heap接口實(shí)現(xiàn),外加一些方法:現(xiàn)在我們的負(fù)載均衡使用堆來跟蹤負(fù)載情況。func(pPool)Less(i,jint)bool{returnp[i].pending<p[j].pending}負(fù)載調(diào)度-Dispatch根據(jù)每個worker的負(fù)載情況,新的請求過來時分配到負(fù)載最低的那個worker。//SendRequesttoworkerfunc(b*Balancer)dispatch(reqRequest){//Grabtheleastloadedworker...w:=heap.Pop(&b.pool).(*Worker)//...sendit

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論