Hello,

2009/3/16 bOR_ <boris.sch...@gmail.com>

>
> Nice! A few more days of work and I've time to play with these kind of
> things again. Here are some comments, based on your description.
>
> As game of life is a cellular automata, you do not need any blocking
> at all, so you could use agents, rather than refs. It does become an
> asynchronous CA then, but that fits for game of life :).
>
> Every cell would be an agent. Agents read the state of their
> neighbouring cells and update their own state. If world is a vector of
> agents, then (doseq [a world] (send a update)) (apply await world)
> would update the whole grid once, using all the processors that java
> can find.


I'm not very used to concurrent programming, so I have a few questions you
may find naïve, but well, let's just pretend they're interesting  ... :

It seems to me that the game of life works in "increments" of its "world".
So I don't see at first what can be gained by using one agent for each cell.
Because then, you'll still have to coordinate the work of the agents in your
code.
I suspect you suggested to use agents because by using agents, you gain an
abstraction for parallel programming for free, and that you are not using
agent for what I think they are for in the first place: asynchronized
computing.

Regards,

-- 
Laurent



>
> On Mar 16, 5:31 am, Scott Fraser <scott.e.fra...@gmail.com> wrote:
> > I have taken Larry's "Game of Life" example that he originally posted
> > here:
> >
> > http://groups.google.com/group/clojure/msg/fdfc88f1ba95bdee
> >
> > ...and updated it to use all the CPU's your JVM has access to. My
> > first attempts ran into the classic map -> pmap slowdown. My next
> > attempt had too much dosync, in that there were many threads but they
> > were all waiting for each other.
> >
> > I finally rewrote the calc-state routine to batch the units of work
> > into meaty sizes, and to minimize the dosync granularity. It gets the
> > batches of new-state together, then goes and applies these in batches.
> > In both events I use pmap.
> >
> > Now it is running really fast on my 4-core Intel i7. You will really
> > notice a difference at larger grid sizes. On my i7 it keeps the 8 (due
> > to hyperthreading) "cpus" busy at about 60% when I run a huge grid.
> >
> > I also updated paint-cells with a type hint that greatly reduces
> > reflection in that performance critical code.
> >
> > I am very new to clojure and would appreciate feedback. I am concerned
> > I may have overcomplicated things with my usage of the map/pmap form.
> > I am guessing there may be a simpler way to write what I did.
> >
> > Note at the start it will automatically select how many "available-
> > procs" you have. Try tweaking this on your hardware to see how it
> > impacts performance. Watching the threads with a profiler is
> > interesting.
> >
> > Here is is:
> >
> > (def cells (ref {}))
> > (def running (ref false))
> > ;(def x-cells ( * 32 4))
> > ;(def y-cells ( * 48 4))
> > (def x-cells 32)
> > (def y-cells 32)
> > (def range-cells (for [x (range x-cells) y (range y-cells)] [x y]))
> > (def length-range-cells (count range-cells))
> > (def cell-size 10)
> > (def life-delay 0)
> > (def life-initial-prob 3)
> > (def available-procs (.. java.lang.Runtime getRuntime
> > availableProcessors))
> >
> > (defn determine-initial-state [x y]
> >   (= 0 (rand-int life-initial-prob)))
> >
> > (defn determine-new-state [x y]
> >   (let [alive (count (for [dx [-1 0 1] dy [-1 0 1]
> >                            :when (and (not (= 0 dx dy))
> >                                    (cells [ (mod (+ x dx) x-cells)
> > (mod (+ y dy) y-cells)]))]
> >                        :alive))]
> >     (if (cells [x y])
> >       (< 1 alive 4)
> >       (= alive 3))))
> >
> > (defn update-batch-of-new-cells [new-cells list-of-batches]
> >   (dosync
> >     (dorun (map #(commute new-cells assoc (first %) (second %))
> >              list-of-batches))
> >     ))
> >
> > (defn calc-batch-of-new-cell-states [cell-state batch-cells]
> >   (doall (map
> >            #(let [new-cell-state (cell-state (first %) (second %))]
> >               [[(first %) (second %)] new-cell-state])
> >            batch-cells)))
> >
> > (defn calc-state [cell-state]
> >   (let [new-cells (ref {})]
> >     (dorun (pmap #(update-batch-of-new-cells new-cells %)
> >              (pmap #(calc-batch-of-new-cell-states cell-state %)
> >                (for [cpu (range available-procs)] (take-nth available-
> > procs (drop cpu range-cells))))))
> >     (dosync (ref-set cells @new-cells))))
> >
> > (defn paint-cells [#^java.awt.Graphics graphics]
> >   (doseq [[[x,y] state] @cells]
> >     (doto graphics
> >       (. setColor (if state Color/RED Color/WHITE))
> >       (. fillRect (* cell-size x) (* cell-size y) cell-size cell-
> > size))))
> >
> > (defn toggle-thread [#^JPanel panel button]
> >   (if @running
> >     (do (dosync (ref-set running false))
> >       (. button (setText "Start")))
> >     (do (dosync (ref-set running true))
> >       (. button (setText "Stop"))
> >       (. (Thread.
> >            #(loop []
> >               (calc-state determine-new-state)
> >               (. panel repaint)
> >               (if life-delay (Thread/sleep life-delay))
> >               (if @running (recur))))
> >         start))))
> >
> > (defn -main[]
> >
> >   (calc-state determine-initial-state)
> >
> >   (let [f (JFrame.)
> >         b (JButton. "Start")
> >         panel (proxy [JPanel] [] (paint [graphics] (paint-cells
> > graphics)))]
> >
> >     (doto f
> >       (. setLayout (BorderLayout.))
> >       (. setLocation 100 100)
> >       (. setPreferredSize (Dimension. (* cell-size x-cells) (+ 60 (*
> > cell-size y-cells))))
> >       (. add b BorderLayout/SOUTH)
> >       (. add panel BorderLayout/CENTER)
> >       (. setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
> >       (. pack)
> >       (. setVisible true))
> >
> >     (. b addActionListener
> >       (proxy [ActionListener] []
> >         (actionPerformed [evt] (toggle-thread panel b))))))
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to