Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using agents to synchronize jobs

I am toying with a simulation where I have couple of robots and a controller, controller decided what to do and assign jobs to robots, following is technically an abuse basically I do not care about the agents state, I just care about the fact that it will execute fns sent to it in order and I can wait for them to finish.

Following pretty much demonstrates what I am trying to achieve, controller gets a big job each robots gets a chunk of it,


(def *agents* (reduce
               (fn[h v] (assoc h v (agent true)))
               {:control (agent true)} (range 0 5)))

(defn send-job [id f]
  (send-off (*agents* id)
            (fn [s f]
              (try
                (f)
                (catch Exception e (println e))))
            f))

(defn await-job [id]
  (await (*agents* id)))

(send-job :control
          (fn []

            (send-job 0 (fn []
                          (Thread/sleep 10)
                          (println "0 Done.")))

            (send-job 1 (fn []
                          (Thread/sleep 2)))

            (await-job 1)
            ;; 0 still running.
            ;; do other stuff...
            ))

Well the problem is you can not send-off from within a send-off I get "Can't await in agent action". Is it possible to do this using clojure's concurrency tools or do I have to re implement a agent like structure?

like image 323
Hamza Yerlikaya Avatar asked Aug 14 '11 10:08

Hamza Yerlikaya


1 Answers

You can send or send-off from within an agent action all you like.

What you cannot, in fact, do, is await for another agent to complete, from within an agent. Just like the message says.

This is a good thing, since allowing to await in an agent obviously leads to possible deadlocks. The point of the clojure concurrency primitives is to make deadlock (and other concurrency-related problems) impossible, if you play by the rules.

IMO your use case is not ideal for agents. They are meant to be an asynchronous point of synchronization, similar to the the inbox queue part of actors. Since you don't need that capability and use them as mere job runners, I think you will be served better with a plain Java ExecutorService.

Also of interest might be the ForkJoin framework, which basically is about forking off small units of a computation as you go and (possibly) waiting for them the moment you need the result.

like image 119
Bendlas Avatar answered Nov 08 '22 07:11

Bendlas