Konkurentné vzory v Go - dai.fmph.uniba.skdai.fmph.uniba.sk/courses/PARA/Prednasky/go2.pdf · msg...

54
Konkurentné vzory v Go (gorutina-kanál-mutex) Peter Borovanský, KAI, I-18, borovan(a)ii.fmph.uniba.sk http://talks.golang.org/2012/waza.slide#1 Channels are one of the most popular features of Go and allow for elegant streamlining of data reading/writing and are most often used to prevent data races. They become particularly powerful when used concurrently, as multiple Go routines can write to the same channel.

Transcript of Konkurentné vzory v Go - dai.fmph.uniba.skdai.fmph.uniba.sk/courses/PARA/Prednasky/go2.pdf · msg...

Konkurentné vzory v Go(gorutina-kanál-mutex)

Peter Borovanský, KAI, I-18, borovan(a)ii.fmph.uniba.sk

http://talks.golang.org/2012/waza.slide#1

Channels are one of the most popular features of Go and allow forelegant streamlining of data reading/writing and are most often usedto prevent data races. They become particularly powerful when usedconcurrently, as multiple Go routines can write to the same channel.

n kompozícia nezávislých výpočtovn spôsob myslenia, ako výpočet (prácu) rozdeliť medzi nezávislých agentovn keďže okolitý svet je paralelný, je to spôsob ako lepšie interagovať s nímn málo kto z nás má skutočne paralelný HW, možno tak 2-, 4-, 8-jadro...

n na jednom procesore paralelizmus neurobíte, ale konkurentný výpočet ánoale ... n konkurentný výpočet na jednom procesore bude pravdepodobne pomalší ako

sekvenčný, takže viac ide o konkurentnú paradigmu (myslenie) ako o čas

Go konkurencia založená na CommunicatingSequentialProcesses (T. Hoare, 1978) poskytuje:n konkurentné procedúry (tzv. gorutiny, 8kB stack)n synchronizáciu a komunikáciu prostredníctvom kanálov, mutexovn príkaz select

http://www.youtube.com/watch?v=f6kdp27TYZs

Konkurencia vs. paralelizmus

Gorutina - príkladGorutina loopForever sa vykonáva ako funkcia loopForever len sa

nečaká na jej výsledok, resp. skončeniepackage mainimport ( "fmt" "math/rand" "time")func loopForever(task string) {

for i := 1; ; i++ { // počítame do nekonečnafmt.Printf("%s:%d\n", task, i)time.Sleep(time.Duration(rand.Intn(500)) *

time.Millisecond) }}func main() {

go loopForever("prvy") // spustenie 1.gorutinygo loopForever("druhy") // spustenie 2.gorutinyvar input string // toto čaká na input, v opačnomfmt.Scanln(&input) // prípade, keď umrie hlavné vláknofmt.Println("main stop")} // umrie v Go všetko...

concurrent.go

GorutinaGorutina nie je corutina (tá má bližšie generátorom, async/await z Python 3.5)n je nezávisle vykonávaná funkcian má vlastný stack 8kB -rastie sa podľa jej potrieb, GO 1.3 (Contiguous stacks)n môže ich byť veľa, aj veľmi veľa (uvidíme ~ 1.000.000)n 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:func main() {

go func /*tu chýba meno fcie*/ (task string) {for i := 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

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álach <- 123

čítanie z kanála je blokujúca operácia, až kým hodnotu niekto nezapíše do kanálax = <-chtakže ide o komunikáciu (prenos dát), ale aj o synchronizáciu rutín/vlákien.

V prípade buffrovaných kanálov make(chan int, 10) prídeme o synchronizáciu, takže to skúsime neskôr...

Komunikácia a synchronizácia(high-level)

Go mantra

•Golang Puzzlers(čo sa stane, keď…)

func main() {ch := make(chan int )

fmt.Println("idem zapisat")ch <- 1fmt.Println("zapisane 1")ch <- 2fmt.Println("zapisane 2")

}

func () {time.Sleep(time.Duration(5 * time.Second))fmt.Println("idem citat")fmt.Printf("precitane %d \n", <- ch )

}

,4

var input string // toto čaká na input, v opačnomfmt.Scanln(&input) // prípade, keď umrie hlavnéfmt.Println("main stop")

channels.go

odeadlock ch<-1osyntax errorodeadlock ch<-2oskončí main§zapisane 1§zapisane 2§idem citat§precitane 1

go

()

Timershttp://divan.github.io/posts/go_concurrency_visualize/

func timer(d time.Duration) (ch chan int) {ch = make(chan int)go func() {

time.Sleep(d)ch <- 1

}()return

}func main() {

for i := 0; i < 24; i++ {c := timer(1 * time.Second)fmt.Println(<-c)

}}

timers.go

koľko gorutín beží zároveň ?•1•2•24•25

http://divan.github.io/demos/timers/

Timers2func timer2(d time.Duration, ch chan int) {

go func() {time.Sleep(d)ch <- 1

}()}

func main() {ch := make(chan int)for i := 0; i < 24; i++ {

timer2(time.Duration(i) * time.Second, ch)}for x := range ch {

fmt.Println(x)}

}

timers2.go

koľko gorutín beží zároveň ?•1•2•24•25

Dvaja píšu, jeden čítafunc loopAndSend(task string, ch chan string) {

for i := 1; i < 30; i++ {ch <- fmt.Sprintf("%s:%d\n", task, i)time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)

}}func main() { // dve gorutiny píšu do

ch := make(chan string) // toho istého kanála chgo loopAndSend("prvy", ch)go loopAndSend("druhy", ch)for { // tu to čítame for msg := range ch {

msg := <-ch // range prebieha obsahom// celého kanála

fmt.Print(msg) fmt.Print(msg)} }fmt.Println("main stop") } // nikdy neskončí, prečo ?concurrent2.go

Funkcia vráti kanálchan string je typ kanála stringov, funkcia ho môže vrátiť ako výsledokfunc loopToChannel(task string) chan string {

ch := make(chan string) // vytvor kanálgo func() { // pusti nezávislú gorutinu

for i := 1; i < 30; i++ { // ktorá píše do kanálach <- fmt.Sprintf("%s:%d\n", task, i)time.Sleep(...) }

}() // argumenty anonymnej funkciereturn ch } // vráť kanál ch:chan string

func main() {ch1 := loopToChannel("prvy")ch2 := loopToChannel("druhy")for {

fmt.Print(<-ch1) // čo dostaneme ???fmt.Print(<-ch2) // chápeme už synchronizáciu ??

}concurrent3.go

Kanálový sútokfunc multiplexor(ch1, ch2 chan string) chan string {

ch := make(chan string)go func() { // prvá gorutina

for { ch <- <-ch1 } // čítaj z ch1 a píš to do ch}()go func() { // druhá gorutina

for { ch <- <-ch2 } // čítaj z ch2 a píš to do ch}()return ch}

func main() {ch1 := loopToChannel("prvy") // tretia gorutinach2 := loopToChannel("druhy") // štvrtá gorutinach := multiplexor(ch1, ch2)for {

fmt.Print(<-ch) } concurrent3.go

Selectselect je príkaz syntaxou podobný switch, à la javafunc multiplexorSelect(ch1, ch2 chan string) chan string {

ch := make(chan string)go func() { // jednu gorutinu sme ušetrili :-)

for {select { // select vykoná niektorý neblokovanýcase val := <-ch1: // komunikačný case-príkaz

ch <- val // ak niekto zapísal do ch1case val := <-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...return ch } concurrent3.go

Select a timeoutfunc multiplexorSelect(ch1, ch2 chan string) chan string {

ch := make(chan string)go func() {

gameOver := time.After(10 * time.Second)for {

select {case val := <-ch1: ch <- valcase ch <- <-ch1:case val := <-ch2: ch <- valcase <-gameOver:

ch <- "GAME OVER\n"close(ch)

} } }()return ch

} concurrent3.go

TimeoutgameOver := time.After(10*time.Second) alebo vlastný kódgameOver := make(chan bool)go func(seconds int) {

time.Sleep(seconds*time.Second)gameOver <- true // timeout

}(10)je kanál už zavretý ?for { fmt.Print( <-ch) } zle skončí, ak close(ch)for {

val, opened := <-ch if !opened {

break} fmt.Print(val)

} concurrent3.go

Ping-Pong (http://divan.github.io/posts/go_concurrency_visualize/)

func main() {var Ball inttable := make(chan int)go player(table)go player(table)

table <- Balltime.Sleep(1 * time.Second)<-table

}

func player(table chan int) {for {

ball := <-tableball++time.Sleep(100 * time.Millisecond)table <- ball

}}

go player(table)

pingpong.go

http://divan.github.io/demos/pingpong/

http://divan.github.io/demos/pingpong3/

Producer-Consumerfunc producer(ch chan int) {

for i := 1; i <= 30; i++ {ch <- ifmt.Println("produce: " + strconv.Itoa(i))//time.Sleep(time.Second) // lenivá produkcia

}}func consumer(ch chan int) {

for i := 1; i <= 30; i++ {fmt.Println("consume: ", <-ch)time.Sleep(time.Second) // lenivá spotreba

}}func main() {

ch := make(chan int, 5) // buffrovaný kanál veľkosti 5go producer(ch) go producer(ch) // 1. a 2. producergo consumer(ch)time.Sleep(100000000000)} // skoro večnosť producerconsumer.go

http://divan.github.io/demos/fanin/

Čínsky šepkárivar number = 1000000func main() {

start := time.Now()

prev := make(chan int)first := prev // ľavé ucho (ľ.u.) nultého šepkárago func() { first <- 0 }() // nultému šepneme 0 do ľ.u.for i := 0; i < number; i++ { // 40000 číňanov

next := make(chan int) // kanál z p.u.i-tehogo func(from, to chan int) { // do ľ.u. i+1-vého

for { to <- 1 + <- from } // šepnem ďalej 1+čo}(prev, next) // počujemprev = next // pokračujem, i k i+1

}elapsed := time.Since(start)

fmt.Println(<-prev) fmt.Println(elapsed)} chinees.go

Prvočísla(Eratosténovo sito)

prev := make(chan int)first := prevgo func() {

for i := 2; ; i++ { first <- i } }() // do first sypeme 2,3,4, …for i := 0; i < 10000; i++ { // čínski preosievači prvočísel

prime := <-prev // prvé preosiate musí byť prvočíslofmt.Println(prime)next := make(chan int) // kanál pre ďalšieho preosievačago func(prime int, from, to chan int) { // číta z from, píše do

for { // do to, vyčiarkne deliteľné primeval := <-from // číta z from – vstupný kanálif val%prime > 0 { // je deliteľné prime ?

to <- val // ak nie je, píš do to - výstupný}

}}(prime, prev, next) // spustenie nezávislého preosievačaprev = next // výsledok ide ďalšiemu osievačovi

} primes.go

Prvočísla(http://divan.github.io/posts/go_concurrency_visualize/)

http://divan.github.io/demos/primesieve/

Quicksort - pivotizáciaNekonkurentná pivotizácia, nepekné dvojité testy …

func pivot(pole []int) int {i, j, pivot := 1, len(pole)-1, pole[0]for i <= j {

// hľadanie maxiputána medzi liliputánmifor i <= j && pole[i] <= pivot { i++ }// hľadanie liliputána medzi maxiputánmifor j >= i && pole[j] >= pivot { j-- }if i < j { // nájdení kandidáti sa vymenia

pole[i], pole[j] = pole[j], pole[i]}

} // pivota pichni medzi liliputánov a maxiputánovpole[0], pole[j] = pole[j], pole[0]return i }quicksort.go

Quicksort func cquickSort(pole []int, done chan bool) {

if len(pole) <= 1 {

} else {index := pivot(pole)

cquickSort(pole[:(index-1)], left)cquickSort(pole[index:], right)

} }

func cquickSort(pole []int, done chan bool) {if len(pole) <= 1 {

done <- true

} else {index := pivot(pole)left, right := make(chan bool), make(chan bool)go cquickSort(pole[:(index-1)], left)go cquickSort(pole[index:], right)done <- (<-left && <-right)

} }

func cquickSort(pole []int, done chan bool) {if len(pole) <= 1 {

done <- true} else if len(pole) < granularity {

squickSort(pole)done <- true

} else {index := pivot(pole)left, right := make(chan bool), make(chan bool)go cquickSort(pole[:(index-1)], left)go cquickSort(pole[index:], right)done <- (<-left && <-right)

} }

quicksort.go

Quicksort výsledkySize Granularity time500.000 500.000 109ms500.000 50.000 62ms500.000 5.000 78ms500.000 500 62ms500.000 50 171ms500.000 5 1375ms500.000 1 niet dosť kanálov...

010002000300040005000600070008000

Rady2

Size Granularity time50.000.000 50.000.000 7s 291ms50.000.000 5.000.000 2s 293ms50.000.000 500.000 1s 951ms50.000.000 50.000 2s 015ms50.000.000 5.000 2s 318ms50.000.000 500 2s 461ms50.000.000 50 5s 663ms50.000.000 5 niet dosť kanálov...

sync.WaitGroup(mutex)

Semafór, alias mutex, je synchronizácia na nižšej úrovni ako kanálpackage mainimport ("fmt" "math/rand" "time" "sync") func loopForever(task string, goGroup *sync.WaitGroup) {

for i := 1; i < 10; i++ { fmt.Printf("%s:%d\n", task, i) time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)

} goGroup.Done() // dekrementovanie mutexu

} func main() {

goGroup := new(sync.WaitGroup) // vytvorenie mutexugoGroup.Add(2) // nastavenie mutexu na 2go loopForever("prvy", goGroup) go loopForever("druhy", goGroup) goGroup.Wait() } // blokuj, kým mutex > 0

concurrent_sync.go

for w := 0; w < 10; w++ {//100xwritergo func() {for {key := rand.Intn(5)val := rand.Intn(100)mutex.Lock()state[key] = valmutex.Unlock()atomic.AddUint64(&writeOps, 1)time.Sleep(time.Millisecond)

}}()

}

Semafór(mutex - https://gobyexample.com/mutexes)

var state = make(map[int] int) //state alias HasmMap<Integer, Integer>var mutex = &sync.Mutex{}var readOps uint64var writeOps uint64for r := 0; r < 100; r++ {//100xreader

go func() {total := 0for {key := rand.Intn(5)mutex.Lock()total += state[key]mutex.Unlock()atomic.AddUint64(&readOps, 1)time.Sleep(time.Millisecond)

}}()

}

mutexes.go

state reader

state writer

Robotníci a lopaty(workers & worker pool)

var WORKERS = runtime.NumCPU(); // pocet jadiervar TASKS = 100;type Task struct { a, b int } // vynasob tieto dve cisla

func worker(id int, ch <-chan Task, wg *sync.WaitGroup) {defer wg.Done()for {

task, ok := <-chif !ok { return } // ak došla robotaresult := task.a*task.b;time.Sleep(time.Duration(math.Log2(float64(result))) * time.Millisecond)

}}

func pool(wg *sync.WaitGroup) {ch := make(chan Task)for i:=0; i<WORKERS; i++ { go worker(i, ch, wg) }for i:=0; i<TASKS; i++ { for j:=0; j<TASKS; j++ { ch<-Task{i, j} } }close(ch) // násobíme i*j, i,j in [1..TASKS]

}

workers.go

Robotníci a lopaty(workers & worker pool)

var WORKERS = runtime.NumCPU(); // pocet jadiervar TASKS = 100;type Task struct { a, b int } // vynasob tieto dve cisla

func worker(id int, ch <-chan Task, wg *sync.WaitGroup) { … }func pool(wg *sync.WaitGroup) { … }func main() {

var wg sync.WaitGroupwg.Add(WORKERS)go pool(&wg)wg.Wait()

}

workers.go

Výplata:$1243 Bits 12205$1248 Bits 12237$1253 Bits 12233$1259 Bits 12241$1245 Bits 12195$1248 Bits 12213$1245 Bits 12184$1259 Bits 12200------------------------------100*100

Fibonacciho agenti(cvičenie)

Vyrobíme niekoľko nezávislých agentov, ktorí

n zipf(ch1, ch2 chan int, f func(int, int) int) chan intspája dvojice prvkov z kanála ch1 a ch2 pomocou funkcie f (u nás +)

n tail(ch1 chan int) chan intčíta z kanála ch1, priamo píše do výstupu, akurát prvý prvok z ch1 zabudne

n func fib1() chan intpodivným spôsobom generuje fibonacciho čisla...aj to len trochu...

n spliter(ch chan int) (ch1 chan int, ch2 chan int)číta z ch, a výsledky konkurentne kopíruje do ch1 aj ch2

fibStream.go

Agent zip(cvičenie)

func zipf(ch1, ch2 chan int, f func(int, int) int) chan int { ch := make(chan int) zipCount++ go func() {

for { f1 := <-ch1 // číta dvojice f1f2 := <-ch2 // f2 z ch1 a ch2ch <- f(f1, f2) // píše f(f1, f2), alias f1+f2

} }() return ch

}

fibStream.go

Agent tail(cvičenie)

func tail(ch1 chan int) chan int { ch := make(chan int) tailCount++ <-ch1 // prvý prvok zabudnego func() {

for { ch <- <-ch1

} }() return ch

}

fibStream.go

Agent fib1(katastrofické výsledky)

func fib1() chan int { ch := make(chan int) fibCount++ go func() {

ch <- 1ch <- 1for val := range zipf(fib1(), tail(fib1()),

func(x, y int) int { return x + y }) { ch <- val

} }() return ch

}

fibStream.go

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)

Agent splitter(cvičenie)

func spliter(ch chan int) (ch1 chan int, ch2 chan int) { ch1 = make(chan int) ch2 = make(chan int) spliterCount++ go func() {

for { val := <-ch // ch1 <- val deadlock! why ?// ch2 <- valgo func() { ch1 <- val }() go func() { ch2 <- val }()

} }() return ch1, ch2

} fibStream.go

Agent fib(prijatelné výsledky ?)

func fib() chan int { ch := make(chan int) fibCount++ go func() {

ch <- 1ch <- 1ch1, ch2 := splitter(fib()) // použitie splitterafor val := range zipf(ch1, tail(ch2),

func(x, y int) int { return x + y }) { ch <- val

} }() return ch

} fibStream.go

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 číslo165580141 (138,135,137, 137)Success: process exited with code 0.

Agent splitter(cvičenie)

func splitter(ch chan int) (ch1 chan int, ch2 chan int) {ch1 = make(chan int) ch2 = make(chan int)splitterCount++go func() {

for { val := <-ch select {

case ch1 <-val: case ch2 <-val:

} }

}() return ch1, ch2

}

B:2 A:1B:3 B:4B:5B:6B:7B:8B:9B:10B:11A:12B:13B:14B:15

B

A

Klobúky ako predjedlo(čo to má s programovaním pochopíte dnes)

n 3 biele a 2 čiernen A, B, C si navzájom vidia farby klobúkovn nesmú komunikovať, ale (aj tak) sú inteligentní Jn vyhrávajú, ak všetci uhádnu farbu svojho klobúkan resp. ak sa jeden pomýli, prehrali všetci.

Hint: A,B,C sú spoluhráči, preto predpokladaj, že sú chytrí a mysli aj za nich

Hint: úloha nie je o šťastí=hádaní správneho riešenia

Do 10 sekúndak vidím dva čierne, určite mám biely, a preto sa

hneď ozvem, že "mám biely".

ak sa niekto do 10s ozval, že má biely, musí vidieť dva čierne, preto ja mám čierny, tak hneď kričím "mám čierny".

inak čakám 10s, nikto neozval, že „mám biely", preto určite nie sú v hre 2 čierne, ale najviac jeden čierny !!!

10 až 20 sekúnd

ak teda vidím čierny, ja musím mať biely, tak sa ozvem hneď, že mám "mám biely".

inak, ak sa ozvú dvaja (do 10 s), že biely, ja mám čierny, tak kričím "mám čierny".

inak, nevidím čierny a nikto sa neozval, čakám ďalších 10s,

v hre je najviac jeden čierny

po 20 sekundách

keďže sa nikto neozval, tak nie je žiaden čierny, tak kričím "mám biely" a ostatní tiež

v hre nie je žiaden čierny

Celý algoritmus(bez vysvetlenia, už pre cvičenú opicu)

ak vidím dva čierne, hneď ozvem, že "mám biely".ak sa niekto do 10 s ozval, tak kričím "mám čierny". inak čakám 10s.

ak vidím čierny, tak hneď kričím "mám biely".inak, ak sa ozvú dvaja do 10 s, tak kričím "mám čierny".

Po 10 sek:

inak čakám ďalších 10s,

kričím "mám biely”Po 20 sek:

Hneď:

Na zamyslenien je podstatné, či kričím mám biely/mám čierny, nestačí len už viem ?!

n Dalo by sa to pre 3 biele, 3 čierne, 3 ľudia ?

n Dalo by sa to pre 2 biele, 1 čierne, 2 ľudia ?

n Dalo by sa to pre N biele, (N-1) čierne, N ľudia ? (napr.6,5,6)

n Dalo by sa to pre >N biele, (N-1) čierne, N ľudia ? (napr. 8,5,6)

n Dalo by sa to pre N biele, <(N-1) čierne, N ľudia ? (napr. 6,4,6)

Komunikácia–každý s každým

Správa, kanály, agentitype Message struct {

who int // od koho, odosielateľwhat int } // čo, obsah správy

func makeChannels(n int) []chan Message { chArray := make([]chan Message, n)for i:= 0; i < n; i++ {// kanál,na ktorom počúva i-ty agent

chArray[i] = make(chan Message)} return chArray

} func main() {

chArray := makeChannels(numb) for a:= 0; a<numb; a++ {

runAgent(a, chArray) } } klobuky/modelBezDispecher.go

Agenti napriamofunc runAgent(agent int, channels []chan Message) {

go func() { // ID agenta, kanaly na vsetkych agentovi := 1 // iniciálny stav agentafor { // loop forevertimeout := time.After(...)select { case msg := <- channels[agent]: // agent počúva len svoj

fmt.Printf("agentovi %d: prišla správa:%s",agent, msg) case <-timeout: // prešiel timeout, vyrobíme správu msg

msg := Message{who:agent, what:i++} //zmeníme svoj stavfor index, ch := range channels { // povedz každémuif index != agent { // okrem seba

go func(cha chan Message) {// !!!!!!!!!!!!!!!!cha <- msg // správu msg

}(ch) klobuky/modelBezDispecher.go

Agenti napriamofunc runAgent(agent int, channels []chan Message) {

go func() { // ID agenta, kanaly na vsetkych agentovi := 1 // iniciálny stav agentafor { // loop forevertimeout := time.After(...)select { case msg := <- channels[agent]: // agent počúva len svoj

fmt.Printf("agentovi %d: prišla správa:%s",agent, msg) case <-timeout: // prešiel timeout, vyrobíme správu msg

msg := Message{who:agent, what:i++} //zmeníme svoj stavfor index, ch := range channels { // povedz každémuif index != agent { // okrem seba

go func() { // !!!!! ZLE !!!!!!ch <- msg // správu msg

}() klobuky/modelBezDispecher.go

Príklad komunikácie 3 agentov1: povedal 1agentovi 2: prisla sprava:"1: povedal 1"agentovi 0: prisla sprava:"1: povedal 1"0: povedal 1agentovi 2: prisla sprava:"0: povedal 1"agentovi 1: prisla sprava:"0: povedal 1"1: povedal 2agentovi 2: prisla sprava:"1: povedal 2"0: povedal 21: povedal 3agentovi 0: prisla sprava:"1: povedal 2"agentovi 0: prisla sprava:"1: povedal 3"agentovi 1: prisla sprava:"0: povedal 2"agentovi 2: prisla sprava:"0: povedal 2"agentovi 2: prisla sprava:"1: povedal 3“

Aplikácia na klobúky(domáca úloha)

n [0s] A: vidim 1 biele a 1 ciernen [0s] A: cakam 10 sekn [0s] C: vidim 1 biele a 1 ciernen [0s] C: cakam 10 sekn [0s] B: vidim 2 biele a 0 ciernen [0s] B: cakam 10 sek

n [10s] B: cakam dalsich 10 sekn [11s] A: mam biely !!! truen [11s] C: mam biely !!! truen [11s] B:: prisla sprava, ze [11s] A: mam biely !!! truen [12s] B: mam cierny !!! truen finito

func vidim(name String) (int, int) {

Komunikácia s dispečerom

Dispatcher čo počujte to prepošle

func runDispatcher(channels []chan Message) chan Message { dispch := make(chan Message)

// kanál na komunikáciu s dispatcheromgo func() { for { msg := <- dispch // ak prišla správafmt.Println("dispecer sa dozvedel: " + msg.toString()) for _,ch := range channels { go func(x chan Message) {

x <- msg}(ch)

} }

}()return dispch } klobuky/modelSDispecher.go

Agenti cez dispečerafunc runAgentCommunicatingWithDispatcher(agent int,

dispch chan Message, input chan Message) { go func() { i := 1 // stav agentafor { timeout := time.After(...) // náhodny delayselect { case msg := <- input: // ak prišla správa agentovi,

fmt.Printf("agentovi %d: prisla sprava:%s",agent,msg) case <-timeout: // po timeout, vytvoríme správu

msg := Message{who:agent, what:i}dispch <- msg // pošleme dispecerovii++ // agent si zvýši stav

} } }() } klobuky/modelSDispecher.go

Agenti cez dispečerafunc runAgentCommunicatingWithDispatcher(agent int,

dispch chan Message, input chan Message) { go func() { i := 0 // stav agentafor { timeout := time.After(...) // náhodny delayselect { case msg := <- input: // ak prišla správa agentovi,

fmt.Printf("agentovi %d: prisla sprava:%s",agent,msg) case <-timeout: // po timeout, vytvoríme správu

msg := Message{who:agent, what:i}go func() { dispch <- msg }()// pošleme dispecerovii++ // agent si zvýši stav

} } }() } klobuky/modelSDispecher.go

Príklad komunikácie 3 agentov1: povedal 0dispecer sa dozvedel: 1: povedal 0agentovi 2: prisla sprava:"1: povedal 0"agentovi 0: prisla sprava:"1: povedal 0"agentovi 1: prisla sprava:"1: povedal 0"0: povedal 0dispecer sa dozvedel: 0: povedal 0agentovi 2: prisla sprava:"0: povedal 0"agentovi 0: prisla sprava:"0: povedal 0"agentovi 1: prisla sprava:"0: povedal 0"0: povedal 1dispecer sa dozvedel: 0: povedal 1agentovi 2: prisla sprava:"0: povedal 1"agentovi 0: prisla sprava:"0: povedal 1"agentovi 1: prisla sprava:"0: povedal 1“

Aplikácia na klobúky(domáca úloha)n [0s] A: vidim 1 biele a 1 ciernen [0s] A: cakam 10 sekn [0s] B: vidim 2 biele a 0 ciernen [0s] B: cakam 10 sekn [0s] C: vidim 1 biele a 1 ciernen [0s] C: cakam 10 sekn [10s] B: cakam dalsich 10 sekn [11s] A: mam biely !!! truen od A prisla sprava, ze [11s] A: mam biely !!! truen [11s] C: mam biely !!! truen [11s] B:: prisla sprava, ze [11s] A: mam biely !!! Truen od C prisla sprava, ze [11s] A: mam biely !!! truen od B prisla sprava, ze [11s] A: mam biely !!! truen od B prisla sprava, ze [11s] C: mam biely !!! truen [12s] B: mam cierny !!! Truen finito

func vidim(name String) (int, int) {

Riešenian je podstatné, či kričím mám biely/mám čierny, stačí len „už viem“ ?!ánon Dalo by sa to pre 3 biele, 3 čierne, 3 ľudia ?nien Dalo by sa to pre 2 biele, 1 čierne, 2 ľudia ?ánon Dalo by sa to pre N biele, (N-1) čierne, N ľudia ? (napr.6,5,6)ánon Dalo by sa to pre >N biele, (N-1) čierne, N ľudia ? (napr. 8,5,6)ánon Dalo by sa to pre N biele, <(N-1) čierne, N ľudia ? (napr. 6,4,6)áno