On Wednesday, 27 July 2016 15:14:13 UTC+3, Carl Ranson wrote:
>
>
> HI all, 
>
> So I figured Conways game of life would be a good exercise to get my feet 
> wet with go. Specifically i wanted to make the calculation of the next 
> board state to be concurrent. 
> I started a separate goroutine for each cell and then used a pair of 
> channels to synchronize updating to the next state and displaying the 
> board. 
>
> Would love to hear opinions on this approach? are their better or more 
> effective ways to do the same thing?
>

Few unorganized thoughts:

First, when parallelizing things, always consider communication as part of 
the computation. Communication can have a significant overhead.

Usually, you should try to ensure that each goroutine does non-trivial 
amount of work.

e.g.

type Bitmap [32][32]bool // can be packed more compactly

type Block struct {
    Active  *Bitmap // = &block.Buffers[0]
    Next    *Bitmap // = &block.Buffers[1], after each computation swap 
Active and Next
    Buffers [2]Bitmap
}
type Field struct {
    Blocks []Block
}

// Alternatively use two fields instead of swapping at block level...

And each goroutine computes some number of the blocks...

http://www.shodor.org/media/content/petascale/materials/UPModules/GameOfLife/Life_Module_Document_pdf.pdf

Try to avoid pointers in a tight loop. Following a pointer is not free.

This can be simplified:
        if c.nw.currentState {
            i++
        }
with
        i += count(c.nw) // define count somewhere

Also take a look at https://golang.org/doc/play/life.go

Of course then there's HashLife, and other that can improve it further.


> Thanks in advance,
> CR
>
>
> package main
>
> import (
>     "fmt"
>     "math/rand"
>     "time"
> )
>
> type Cell struct {
>     x            int
>     y            int
>     currentState bool
>     nw           *Cell
>     n            *Cell
>     ne           *Cell
>     e            *Cell
>     se           *Cell
>     s            *Cell
>     sw           *Cell
>     w            *Cell
> }
>
> func (c *Cell) cell(runChan chan string, doneChan chan string) {
>     for {
>         // wait until we're allowed to proceed
>         _ = <-runChan
>
>         // count the number of neighbours
>         var i int = 0
>         if c.nw.currentState {
>             i++
>         }
>         if c.n.currentState {
>             i++
>         }
>         if c.ne.currentState {
>             i++
>         }
>         if c.e.currentState {
>             i++
>         }
>         if c.se.currentState {
>             i++
>         }
>         if c.s.currentState {
>             i++
>         }
>         if c.sw.currentState {
>             i++
>         }
>         if c.w.currentState {
>             i++
>         }
>
>         //  Any live cell with fewer than two live neighbours dies, as if 
> caused by under-population.
>         //  Any live cell with two or three live neighbours lives on to 
> the next generation.
>         //  Any live cell with more than three live neighbours dies, as 
> if by over-population.
>         //  Any dead cell with exactly three live neighbours becomes a 
> live cell, as if by reproduction.
>
>         nextState := c.currentState
>         if c.currentState == true {
>             if i < 2 {
>                 nextState = false
>             } else if i == 2 {
>                 nextState = true
>             } else if i == 3 {
>                 nextState = true
>             } else if i > 3 {
>                 nextState = false
>             }
>         } else {
>             if i == 3 {
>                 nextState = true
>             }
>         }
>
>         //fmt.Println("calc for ", c.x, c.y, c.currentState, nextState, i)
>
>         // report that we're finished the calc
>         doneChan <- "done"
>
>         // wait for permission to continue
>         _ = <-runChan
>         c.currentState = nextState
>
>         // report that we've done the transition
>         doneChan <- "done"
>
>         //fmt.Println("assign")
>     }
> }
>
> func ring(x int, size int) int {
>     // this corrects x to be in the range 0..size-1
>     if x < 0 {
>         return size + x
>     } else if x >= size {
>         return 0
>     } else {
>         return x
>     }
> }
>
> func main() {
>     const iterations = 10
>     const gridSize = 50
>     const numCells = gridSize * gridSize
>
>     r := rand.New(rand.NewSource(123))
>     var cells [numCells]Cell
>
>     // set up the cells
>     for y := 0; y < gridSize; y++ {
>         for x := 0; x < gridSize; x++ {
>             cells[x+gridSize*y].x = x
>             cells[x+gridSize*y].y = y
>             cells[x*gridSize+y].currentState = r.Intn(4) == 0
>
>             cells[x+gridSize*y].nw = &cells[ring(x-1, gridSize)+gridSize*
> ring(y-1, gridSize)]
>             cells[x+gridSize*y].n = &cells[ring(x, gridSize)+gridSize*ring
> (y-1, gridSize)]
>             cells[x+gridSize*y].ne = &cells[ring(x+1, gridSize)+gridSize*
> ring(y-1, gridSize)]
>             cells[x+gridSize*y].e = &cells[ring(x+1, gridSize)+gridSize*
> ring(y, gridSize)]
>             cells[x+gridSize*y].se = &cells[ring(x+1, gridSize)+gridSize*
> ring(y+1, gridSize)]
>             cells[x+gridSize*y].s = &cells[ring(x, gridSize)+gridSize*ring
> (y+1, gridSize)]
>             cells[x+gridSize*y].sw = &cells[ring(x-1, gridSize)+gridSize*
> ring(y+1, gridSize)]
>             cells[x+gridSize*y].w = &cells[ring(x-1, gridSize)+gridSize*
> ring(y, gridSize)]
>         }
>     }
>
>     calcChan := make(chan string)
>     readyChan := make(chan string)
>
>     // start a goroutine for each cell
>     for i := 0; i < numCells; i++ {
>         go cells[i].cell(calcChan, readyChan)
>     }
>
>     for x := 0; x < iterations; x++ {
>
>         // display board
>         for y := 0; y < gridSize; y++ {
>             for x := 0; x < gridSize; x++ {
>                 if cells[x+gridSize*y].currentState {
>                     fmt.Print("X")
>                 } else {
>                     fmt.Print(" ")
>                 }
>             }
>             fmt.Println("")
>         }
>
>         fmt.Println("start the calucation")
>         for i := 0; i < numCells; i++ {
>             calcChan <- ""
>         }
>
>         fmt.Println("waiting for calculations to complate")
>         for i := 0; i < numCells; i++ {
>             _ = <-readyChan
>         }
>
>         fmt.Println("start the transition")
>         for i := 0; i < numCells; i++ {
>             calcChan <- ""
>         }
>
>         fmt.Println("waiting for transition to complate")
>         for i := 0; i < numCells; i++ {
>             _ = <-readyChan
>         }
>
>         fmt.Println("calculations done. ")
>     }
>     time.Sleep(2000)
>
>     fmt.Println("Done")
>
> }
>
>
>
>

-- 
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to