1 / 21

Konkurencia vs. paralelizmus

Konkurencia vs. paralelizmus. k ompo zícia nezávislých výpočtov spôsob myslenia, ako výpočet (pr ácu ) rozdeliť medzi nezávislých agentov keďže okolitý svet je paralelný, je to spôsob ako lepšie interagovať s ním málo kto z nás má skutočne paralelný HW, max. tak 2-,4-, 8-jadro...

Download Presentation

Konkurencia vs. paralelizmus

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Konkurencia vs. paralelizmus • kompozícia nezávislých výpočtov • spôsob myslenia, ako výpočet (prácu) rozdeliť medzi nezávislých agentov • keďže okolitý svet je paralelný, je to spôsob ako lepšie interagovať s ním • málo kto z nás má skutočne paralelný HW, max. tak 2-,4-, 8-jadro... • na jednom procesore paralelizmus neurobíte, ale konkurentný výpočet áno ale ... • konkurentný výpočet na jednom procesore budepravdepodobne pomalší ako sekvenčná verzia, takže viac ide o konkurentnú paradigmu ako o čas Go konkurencia založená na CommunicatingSequentialProcesses (T. Hoare, 1978) poskytuje: • konkurentné procedúry (tzv. gorutiny) • synchronizáciu a komunikáciu prostredníctvom kanálov • príkaz select http://www.youtube.com/watch?v=f6kdp27TYZs

  2. Gorutina - príklad Gorutina loopForever sa vykonáva ako funkcia loopForever len sa nečaká na jej výsledok, resp. skončenie packagemain  import("fmt""math/rand""time") funcloopForever(taskstring){ fori:=1;;i++{// počítame do nekonečna fmt.Printf("%s:%d\n",task,i) time.Sleep(time.Duration(rand.Intn(500))*time.Millisecond)}} funcmain(){ goloopForever("prvy") // spustenie 1.gorutiny goloopForever("druhy")// spustenie 2.gorutiny varinputstring// toto čaká na input, v opačnom     fmt.Scanln(&input)// prípade, keď umrie hlavné vlákno fmt.Println("mainstop")} // umrie v Go všetko... concurrent1.go

  3. Gorutina Gorutina • je nezávisle vykonávaná funkcia • má vlastný stack, ktorý rastie/scvrkáva sa podľa jej potrieb • môže ich byť veľa, aj veľmi veľa (uvidíme ~ 100.000) • je to menej ako vlákno (thread), ale k nemu to má najbližšie Anonymná gorutina je de-facto bezmenná funkcia, ktorú aj hneď zavoláme: funcmain(){ gofunc/*tu chýba meno fcie*/ (taskstring){ fori:=1;;i++{// počítame do nekonečna fmt.Printf("%s:%d\n",task,i) time.Sleep(...) } }("prvy")// tu hneď voláme anonymnú fciu s argumentom

  4. Komunikácia a synchronizácia Pomocou kanálov (nebuffrovaná verzia): var ch chan int resp. ch := make(chan int) ch = make(chan int) zápis do kanála je blokujúca operácia, kým hodnotu niekto neprečíta z kanála ch <- 123 čítanie z kanála je blokujúca operácia, až kým hodnotu niekto nezapíše do kanála x = <-ch takže ide o komunikáciu (prenos dát), ale aj o synchronizáciu. V prípade buffrovaných kanálov make(chan int, 10)prídeme o synchronizáciu, tažke to skúsime neskôr, ak vôbec...

  5. Dvaja píšu, jeden číta funcloopAndSend(taskstring,chchanstring){ fori:=1;i<100;i++{ ch<-fmt.Sprintf("%s:%d\n",task,i) time.Sleep(time.Duration(rand.Intn(500))*time.Millisecond) }} funcmain(){ // dve gorutiny píšu do ch:=make(chanstring)// toho istého kanála ch goloopAndSend("prvy",ch) goloopAndSend("druhy",ch) for{ // tu to čítameformsg := range ch { msg:=<-ch// range prebieha obsahom // celého kanála fmt.Print(msg)fmt.Print(msg) }} fmt.Println("mainstop")}//nikdy neskončí, prečo ? concurrent2.go

  6. Funkcia vráti kanál chan string je typ kanála stringov, funkcia ho môže vrátiť ako výsledok funcloopToChannel(taskstring)chanstring{ ch:=make(chanstring)// vytvor kanál gofunc(){// pusti nezávislú gorutinu fori:=1;i<100;i++{ // ktorá píše do kanála ch<-fmt.Sprintf("%s:%d\n",task,i) time.Sleep(...)} }()// argumenty anonymnej funkcie returnch }// vráť kanál ch:chan string funcmain(){ ch1:=loopToChannel("prvy") ch2:=loopToChannel("druhy") for{ fmt.Print(<-ch1) // čo dostaneme ??? fmt.Print(<-ch2) // chápeme už synchronizáciu ?? } concurrent3.go

  7. Kanálový sútok funcmultiplexor(ch1,ch2chanstring)chanstring{ ch:=make(chanstring) gofunc(){ // prvá gorutina for{ch<-<-ch1} // čítaj z ch1 a píš to do ch }() gofunc(){// druhá gorutina for{ch<-<-ch2}// čítaj z ch2 a píš to do ch }() returnch} funcmain(){ ch1:=loopToChannel("prvy") // tretia gorutina ch2:=loopToChannel("druhy")// štvrtá gorutina ch:=multiplexor(ch1,ch2) for{ fmt.Print(<-ch)} concurrent3.go

  8. Select select je príkaz syntaxou podobný switch, à la java funcmultiplexorSelect(ch1,ch2chanstring)chanstring{ ch:=make(chanstring) gofunc(){// jednu gorutinu sme ušetrili :-) for{ select{// select vykoná niektorý neblokovaný caseval:=<-ch1:// komunikačný case-príkaz ch<-val// ak niekto zapísal do ch1 caseval:=<-ch2:// číta sa z ch1, ak ch2, ch<-val// tak z ch2, inak je blokovaný } }// select odpáli nejaká komunikačná udalosť // (zápis/čítanie z/do kanála) v case príkazoch }()// alebo timeout... returnch } concurrent3.go

  9. Select a timeout funcmultiplexorSelect(ch1,ch2chanstring)chanstring{ ch:=make(chanstring) gofunc(){ gameOver:=time.After(10*time.Second) for{ select{ caseval:=<-ch1:ch<-val caseval:=<-ch2:ch<-val case<-time.After(200*time.Millisecond): ch<-"tolate!!!\n" case<-gameOver: ch<-"GAMEOVER\n" close(ch) } }}()returnch} concurrent3.go

  10. Producer-Consumer funcproducer(chchanint){ fori:=1;i<=30;i++{ ch <-i fmt.Println("produce:"+strconv.Itoa(i)) //time.Sleep(time.Second)// lenivá produkcia }} funcconsumer(chchanint){ fori:=1;i<=30;i++{ fmt.Println("consume:",<-ch) time.Sleep(time.Second) // lenivá spotreba }} funcmain(){ ch:=make(chanint,5)// buffrovaný kanál goproducer(ch) goconsumer(ch) time.Sleep(100000000000)}// skoro večnosť producerconsumer.go

  11. Čínsky šepkári varnumber=100000 funcmain(){ start:=time.Now() prev:=make(chanint) first:=prev// ľavé ucho (ľ.u.) nultého šepkára gofunc(){first<-0}() // nultému šepneme 0 do ľ.u. fori:=0;i<number;i++{// 40000 číňanov next:=make(chanint)// kanál z p.u.i-teho gofunc(from,tochanint){// do ľ.u. i+1-vého for{to<-1+< from}// šepnem ďalej 1+čo }(prev,next) // počujem prev=next // pokračujem, i k i+1 } elapsed:=time.Since(start) fmt.Println(<-prev)fmt.Println(elapsed)} chinees.go

  12. Prvočísla(Eratosténovo sito) prev:=make(chanint) first:=prev gofunc(){ fori:=2;;i++{first<-i}}()// do first sypeme 2,3,4, … fori:=0;i< 10000;i++{ // čínski preosievači prvočísel prime:=<-prev// prvé preosiate musí byť prvočíslo fmt.Println(prime) next:=make(chanint)// kanál pre ďalšieho preosievača gofunc(primeint,from,tochanint){// číta z from, píše do for{// do to, vyčiarkne deliteľné prime val:=<-from// číta z from – vstupný kanál ifval%prime>0{// je deliteľné prime ? to<-val// ak nie je, píš do to - výstupný } } }(prime,prev,next)// spustenie nezávislého preosievača prev=next// výsledok ide ďalšiemu osievačovi } chineprimes.go

  13. Quicksort - pivotizácia Nekonkurentná pivotizácia, nepekné dvojité testy … funcpivot(pole[]int)int{ i,j,pivot:=1,len(pole)-1,pole[0] fori<=j{ // hľadanie maxiputána medzi liliputánmi fori<=j&&pole[i]<=pivot{i++} // hľadanie liliputána medzi maxiputánmi forj>=i&&pole[j]>=pivot{j--} ifi<j{// nájdení kandidáti sa vymenia pole[i],pole[j]=pole[j],pole[i] } }// pivota pichni medzi liliputánov a maxiputánov pole[0],pole[j]=pole[j],pole[0] returni } quicksort.go

  14. Quicksort funccquickSort(pole[]int,donechanbool){ iflen(pole)<=1{ done<-true }else{ index:=pivot(pole) left,right:=make(chanbool),make(chanbool) gocquickSort(pole[:(index-1)],left) gocquickSort(pole[index:],right) done<-(<-left&&<-right) } } funccquickSort(pole[]int,donechanbool){ iflen(pole)<=1{ done<-true }elseiflen(pole)<granularity{ squickSort(pole) done<-true }else{ index:=pivot(pole) left,right:=make(chanbool),make(chanbool) gocquickSort(pole[:(index-1)],left) gocquickSort(pole[index:],right) done<-(<-left&&<-right) } } funccquickSort(pole[]int,donechanbool){ iflen(pole)<=1{ }else{ index:=pivot(pole) cquickSort(pole[:(index-1)],left) cquickSort(pole[index:],right) } } quicksort.go

  15. Quicksort výsledky Size Granularity time 500.000500.000 109ms 500.00050.000 62ms 500.0005.000 78ms 500.000500 62ms 500.00050 171ms 500.0005 1375ms 500.000 1 niet dosť kanálov...

  16. Fibonacciho agenti Vyrobíme niekoľko nezávislých agentov, ktorí • zipf(ch1,ch2chanint,ffunc(int,int)int)chanint spája dvojice prvkov z kanála ch1 a ch2 pomocou funkcie f (u nás +) • tail(ch1chanint)chanint číta z kanála ch1, priamo píše do výstupu, akurát prvý prvok z ch1 zabudne • funcfib1()chanint podivným spôsobom generuje fibonacciho čisla... aj to len trochu... • spliter(chchanint)(ch1chanint,ch2chanint) číta z ch, a výsledky konkurentne kopíruje do ch1 aj ch2

  17. Agent zip funczipf(ch1,ch2chanint,ffunc(int,int)int)chanint{ ch:=make(chanint) zipCount++ gofunc(){ for{ f1:=<-ch1 // číta dvojice f1 f2:=<-ch2 // f2 z ch1 a ch2 ch<-f(f1,f2)// píše f(f1, f2), alias f1+f2 } }() returnch } fibStream.go

  18. Agent tail functail(ch1chanint)chanint{ ch:=make(chanint) tailCount++ <-ch1 // prvý prvok zabudne gofunc(){ for{ ch<-<-ch1 } }() returnch } fibStream.go

  19. Agent fib1(katastrofické výsledky) funcfib1()chanint{ ch:=make(chanint) fibCount++ gofunc(){ ch<-1 ch<-1 forval:=rangezipf(fib1(),tail(fib1()), func(x,yint)int{returnx+y}){ ch<-val } }() returnch } fib (fibCount, zipCount, tailCount) 1 (1,0,0) 1 (1,0,0) 2 (7,1,3) 3 (23,7,11) 5 (63,31,31) 8 (255,71,127) 13 (1023,255,511) 21 (2111,1023,1055) 34 (8191,4095,4095) fibStream.go

  20. Agent splitter funcspliter(chchanint)(ch1chanint,ch2chanint){ ch1=make(chanint) ch2=make(chanint) spliterCount++ gofunc(){ for{ val:=<-ch //ch1<-valdeadlock!why? //ch2<-val gofunc(){ch1<-val}() gofunc(){ch2<-val}() } }() returnch1,ch2 } fibStream.go

  21. 1 (1,0,0, 0) 1 (1,0,0, 0) 2 (5,2,4, 4) 3 (8,6,7, 7) 5 (12,9,11, 11) 8 (15,13,14, 14) 13 (19,16,18, 18) 21 (22,20,21, 21) .......... 40.Fibonacciho číslo 165580141 (138,135,137, 137) Success: process exited with code 0. Agent fib(prijatelné výsledky) funcfib()chanint{ ch:=make(chanint) fibCount++ gofunc(){ ch<-1 ch<-1 ch1,ch2:=splitter(fib()) // použitie splittera forval:=rangezipf(ch1,tail(ch2), func(x,yint)int{returnx+y}){ ch<-val } }() returnch } fibStream.go

More Related