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