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

下載本文檔

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

文檔簡(jiǎn)介

并發(fā)(Concurrency)

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

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

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

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

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

<

9

>

>|

分享

?9

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

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

"我用4個(gè)處理器來(lái)執(zhí)行素?cái)?shù)篩選程序,但程序執(zhí)行的更慢了!"

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

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

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

而并行是指同時(shí)能完成很多事情。

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

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

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

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

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

還有,這些地鼠需要能同時(shí)工作。

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

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

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

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

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

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

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

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

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

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

//fstartsrunning

g()

//doesnotwaitforftoreturn

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

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

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

堆棧初始很小,但隨著需求會(huì)增長(zhǎng)或收縮。

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

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

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

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

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

通道是first-class值typeRequeststruct{fnfunc()int//Theoperationtoperform.cchanint//Thechanneltoreturntheresult.}負(fù)載產(chǎn)生者沒(méi)有實(shí)際用處,但能很好的模擬一個(gè)請(qǐng)求者,一個(gè)負(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定義一些請(qǐng)求通道,加上一些負(fù)載記錄數(shù)據(jù)。typeWorkerstruct{requestschanRequest//worktodo(bufferedchannel)pendingint

//countofpendingtasksindexint

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

每個(gè)響應(yīng)直接反饋給它的請(qǐ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ù)載均衡器需要一個(gè)裝很多worker的池子和一個(gè)通道來(lái)讓請(qǐng)求者報(bào)告任務(wù)完成情況。typePool[]*WorkertypeBalancerstruct{poolPooldonechan*Worker}負(fù)載均衡函數(shù)簡(jiǎn)單!你只需要實(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}}}儲(chǔ)存通道的堆(heap)負(fù)載均衡的worker池子是一個(gè)Heap隊(duì)列。

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

溫馨提示

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

評(píng)論

0/150

提交評(píng)論