使用代理同步作业

时间:2011-08-14 10:19:58

标签: concurrency clojure agent

我正在玩弄一个模拟,我有几个机器人和一个控制器,控制器决定做什么,并为机器人分配工作,以下在技术上是滥用基本上我不关心代理状态,我只关心事实上,它将按顺序执行发送给它的fns,我可以等待它们完成。

以下几乎演示了我想要实现的目标,控制器在每个机器人获得一大块资源时获得了巨大的成就,


(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...
            ))

问题是你不能在发送中发送我得到“无法在代理行动中等待”。是否可以使用clojure的并发工具来实现这一点,还是必须重新实现类似结构的代理?

1 个答案:

答案 0 :(得分:6)

您可以通过代理操作发送或发送所有您喜欢的内容。

实际上,您不能在代理内部等待其他代理完成。就像消息所说的那样。

这是一件好事,因为允许在代理中等待显然会导致死锁。如果你遵守规则,那么clojure并发原语的目的是使死锁(以及其他与并发相关的问题)变得不可能。

IMO您的使用案例不适合代理商。它们是一个异步的同步点,类似于actor的inbox queue部分。由于您不需要该功能并将它们仅仅用作工作运行者,我认为使用普通Java ExecutorService可以更好地为您提供服务。

同样令人感兴趣的是ForkJoin框架,它基本上是在你去的时候分离计算的小单位,并且(可能)在你需要结果时等待它们。