Hi Boris,

Just digging a little deeper into your code, and I'm convinced that
the global time ref is the problem:

; you currently have:
(defn do-year  "Calculate one year"  [_]
   (send (agent nil) inc-year)  ; this seems to be totally wrong
; global year gets updated to year+1
; you start 8 agents at once, so year gets +8 if the inc can go
through before any dereffing
; if dereffing occurs then with 8 agents dereffing i can imagine a
transaction timeout occuring
; most likely scenario all agents operate on year 8, but subject to
race conditions.
   (doseq [a (shuffle-java [birth death infect infect evolve evolve
evolve evolve evolve])
           i (shuffle-java (range popsize))]
     (a i)))

Also if I may comment...
What is the purpose of shuffling the functions and the order of world
location visits? It has not introduced any real randomization... what
it does is shuffle the order of functions once, then applies all of
the functions in that particular order to every world location.
(visiting them in a shuffled order, but they all get visited and have
the functions applied in the same order). The only randomization is
that evolve may happen before birth before death, but that will happen
in the same order for all locations for that year.
I think you actually want to do something different like either:
1) death checks at every location, birth checks at every location,
infection checks, evolve checks
2) randomly apply events
3) a combination: standard age death check for every living entity,
total pop birth rate check, random infections/evolutions based on
probabilities applied only as needed

>From what I've seen what you are modeling is a simulation where every
year events occur and modify locations. This sounds chronologically
driven so you wouldn't want separate threads doing separate years as
there is a dependency (year 1 must occur before year 2, before year
3)... So a more sensible way to split up the work would be to process
1/8th of the locations per thread (for your 8 cpus).

But if you wanted to use agents to model the problem instead of as a
threading mechanism, you could treat every location as an agent, then
you can simply shoot off modifications for an entire year and let god
sort the mess out. If performance is your goal then splitting the work
explicitly has the least overhead due to context switching. In the
performance case you'd also want to limit contention as much as
possible by eg: where multiple threads use gathered living, instead
pass the living gathering as an input so that it doesn't need to be
calculated multiple times (which in turn is causing derefs)


Regards,
Tim.






--~--~---------~--~----~------------~-------~--~----~
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