Here is another solution: package pubsub import ( "fmt" "math/rand" "strings" "time" )
type Node struct { Id int State int ChOutL chan int ChOutR chan int ChInL chan int ChInR chan int ChIO chan int } func NewNode(id int, state int) Node { choutL := make(chan int) choutR := make(chan int) var chinL chan int var chinR chan int chIO := make(chan int) return Node{id, state, choutL, choutR, chinL, chinR, chIO} } func (p *Node) Broadcast() { for item := range p.ChIO { rnd := rand.Intn(2) if rnd == 0 { p.ChOutL <- item + 1 } else { p.ChOutR <- item + 1 } fmt.Printf("%d: %d %s\n", p.Id, item, strings.Repeat("*", item)) } } func (p *Node) Listen() { for { time.Sleep(100 * time.Millisecond) select { case inItem := <-p.ChInL: p.ChIO <- inItem case inItem := <-p.ChInR: p.ChIO <- inItem } } } On Sunday, 14 November 2021 at 18:21:00 UTC+1 seank...@gmail.com wrote: > that's exponential growth, every value results in 2 output values > input "1" x1, get "2" x2, "3" x4, "4" x8, "5" x16, ... > also your use of goroutines to send mean you'll still run out of memory at > some point > > On Sunday, November 14, 2021 at 2:29:26 PM UTC Serge Hulne wrote: > >> Hi, >> >> I am trying to code an observer pattern or a publish/submit pattern for a >> sort of cellular automaton. >> >> The classical observer pattern does not to the trick because if a cell A >> subscribes to changes in a cell B and vice-versa, the application will run >> out of stack owing to the recursive approach (B.update() will call >> A.update() and so on and the app will run out of stack). >> >> So I though about using a publish/subscribe pattern where respective >> cells pass each other messages, rather than calling each other's update() >> methods. >> >> Here is a simple example with two cells A and B: >> >> ``` >> package main >> >> import ( >> "fmt" >> ps "publish/pubsub" >> ) >> >> func main() { >> >> fmt.Printf("Starting\n") >> >> chEnd := make(chan int) >> >> // initialize >> a := ps.NewNode(1, 0) >> b := ps.NewNode(2, 0) >> >> // connect nodes >> a.Connect(b.ChOut) >> b.Connect(a.ChOut) >> >> // Start listening >> a.Listen() >> b.Listen() >> >> // Start sending data on one arbitrary node >> // to start the process. >> a.ChIn <- 10 >> >> <-chEnd >> } >> ``` >> and the corresponding lib >> >> ```package lib >> >> import ( >> "fmt" >> ) >> >> type Node struct { >> Id int >> State int >> ChOut chan int >> ChIn chan int >> } >> >> func NewNode(id int, state int) Node { >> chout := make(chan int) >> var chin chan int >> return Node{id, state, chout, chin} >> } >> >> func (p *Node) Broadcast(inItem int) { >> p.ChOut <- inItem + 1 >> //time.Sleep(100 * time.Millisecond) >> } >> >> func (p *Node) Listen() { >> go func() { >> for { >> select { >> case inItem := <-p.ChIn: >> fmt.Printf("%d: %d\n", p.Id, inItem) >> p.Broadcast(inItem) >> } >> } >> }() >> } >> >> func (p *Node) Connect(ch chan int) { >> p.ChIn = ch >> } >> ``` >> Each node has a input and an output channe. >> The input channel of B is the output channel of A and vice-versa. >> >> Every update consists merely of incrementing the data passed by the other >> cell. >> >> It seems to work. So far, so good. >> >> I tried to with a set of 4 cells A, B, C, D, in order to simulate a one >> dimensional cellular automaton of sorts. >> >> In this second attempt, >> >> - each cell has two input channels (let and right) to listen to its >> closest left- and right-hand neighbour, respectively (ChinL and ChinR). >> - each cell has to output channels to communicate its latest updated >> state to its closest neighbours (ChoutL and ChoutR). >> >> I must have done something wrong in the implementation of that scheme >> with 4 cells, because it yields odd results : the values passed back and >> forth between the 4 cells seem to hit a threshold instead of increasing at >> every consecutive step: here is the code: >> >> ``` >> package main >> >> import ( >> "fmt" >> ps "publish/pubsub" >> ) >> >> func main() { >> >> fmt.Printf("Starting\n") >> >> chEnd := make(chan int) >> >> // initialize >> a := ps.NewNode(1, 0) >> b := ps.NewNode(2, 0) >> c := ps.NewNode(3, 0) >> d := ps.NewNode(4, 0) >> >> // connect nodes >> a.ChInL = d.ChOutR >> a.ChInR = b.ChOutL >> >> b.ChInL = a.ChOutR >> b.ChInR = c.ChOutL >> >> c.ChInL = b.ChOutR >> c.ChInR = d.ChOutL >> >> d.ChInL = c.ChOutR >> d.ChInR = a.ChOutL >> >> // Start listening >> go a.Listen() >> go b.Listen() >> go c.Listen() >> go d.Listen() >> >> go a.Broadcast() >> go b.Broadcast() >> go c.Broadcast() >> go d.Broadcast() >> >> // Start sending data on one arbitrary node >> // to start the process. >> a.ChInL <- 1 >> >> // Dummy read on channel to make main() wait >> <-chEnd >> } >> >> /* >> A B C D >> LR LR LR LR >> */ >> >> ``` >> >> and the corresponding lib >> >> ``` >> package main >> >> import ( >> "fmt" >> ps "publish/pubsub" >> ) >> >> func main() { >> >> fmt.Printf("Starting\n") >> >> chEnd := make(chan int) >> >> // initialize >> a := ps.NewNode(1, 0) >> b := ps.NewNode(2, 0) >> c := ps.NewNode(3, 0) >> d := ps.NewNode(4, 0) >> >> // connect nodes >> a.ChInL = d.ChOutR >> a.ChInR = b.ChOutL >> >> b.ChInL = a.ChOutR >> b.ChInR = c.ChOutL >> >> c.ChInL = b.ChOutR >> c.ChInR = d.ChOutL >> >> d.ChInL = c.ChOutR >> d.ChInR = a.ChOutL >> >> // Start listening >> go a.Listen() >> go b.Listen() >> go c.Listen() >> go d.Listen() >> >> go a.Broadcast() >> go b.Broadcast() >> go c.Broadcast() >> go d.Broadcast() >> >> // Start sending data on one arbitrary node >> // to start the process. >> a.ChInL <- 1 >> >> // Dummy read on channel to make main() wait >> <-chEnd >> } >> >> /* >> A B C D >> LR LR LR LR >> */ >> >> ``` >> >> package pubsub >> >> import ( >> "fmt" >> "strings" >> ) >> >> type Node struct { >> Id int >> State int >> ChOutL chan int >> ChOutR chan int >> ChInL chan int >> ChInR chan int >> ChIO chan int >> } >> >> func NewNode(id int, state int) Node { >> choutL := make(chan int) >> choutR := make(chan int) >> var chinL chan int >> var chinR chan int >> chIO := make(chan int) >> return Node{id, state, choutL, choutR, chinL, chinR, chIO} >> } >> >> func (p *Node) Broadcast() { >> for item := range p.ChIO { >> p.ChOutL <- item + 1 >> p.ChOutR <- item + 1 >> fmt.Printf("%d: %d %s\n", p.Id, item, strings.Repeat("*", item)) >> } >> } >> >> func (p *Node) Listen() { >> for { >> //time.Sleep(100 * time.Millisecond) >> select { >> case inItem := <-p.ChInL: >> go func() { >> p.ChIO <- inItem >> }() >> case inItem := <-p.ChInR: >> go func() { >> p.ChIO <- inItem >> }() >> } >> } >> } >> >> ``` >> >> >> >> >> >> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/b5d0248c-4d47-493b-b983-e6efa0fba297n%40googlegroups.com.