Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在搜索不断增长的解决方案空间时使用哪种clojure并行技术?_Clojure_Parallel Processing - Fatal编程技术网

在搜索不断增长的解决方案空间时使用哪种clojure并行技术?

在搜索不断增长的解决方案空间时使用哪种clojure并行技术?,clojure,parallel-processing,Clojure,Parallel Processing,在Clojure中,当处理的每个作业都可以完全孤立地发生并且可能生成需要评估的其他作业列表时,执行并行处理的正确方法是什么 我的实际问题是一个营养计算问题,但我将把它放在国际象棋的形式中,它与我的计算具有相同的问题空间特征 假设,例如,我试图在一盘国际象棋中找到所有将死的招式。在搜索董事会状态时,我会从20个可能的状态开始,每个状态代表一个不同的可能开始移动。每一个都需要评估、接受或拒绝,然后对于每个接受的移动,将创建一个新的工作列表,代表所有可能的下一步移动。这些工作如下所示: initial

在Clojure中,当处理的每个作业都可以完全孤立地发生并且可能生成需要评估的其他作业列表时,执行并行处理的正确方法是什么

我的实际问题是一个营养计算问题,但我将把它放在国际象棋的形式中,它与我的计算具有相同的问题空间特征

假设,例如,我试图在一盘国际象棋中找到所有将死的招式。在搜索董事会状态时,我会从20个可能的状态开始,每个状态代表一个不同的可能开始移动。每一个都需要评估、接受或拒绝,然后对于每个接受的移动,将创建一个新的工作列表,代表所有可能的下一步移动。这些工作如下所示:

initial: '([] proposed-move)
accepted: '([move] proposed-response)
          '([move move] proposed-response)
(def jobs (chan))
(def solutions (chan))
(def accepted-solutions (atom (vector)))

(go (loop [job (<! jobs)]
      (when job
        (go (doseq [solution (process-job-into-solutions job)]
              (>! solutions)))
        (recur (<! jobs)))))

(go (loop [solution (<! solutions)]
      (when (acceptable? solution)
        (swap! accepted-solutions conj solution)
        (doseq [new-job (generate-new-jobs solution)]
          (>! jobs))
        (recur (<! solutions)))))

(>!! jobs initial-job)
要计算的状态数随着每次计算的结果而增加,并且每个状态都可以完全独立于所有其他状态进行计算

我正在使用的解决方案如下:

; a list of all final solutions, each of which is a sequence of moves
(def solutions (agent []))
; a list of all jobs pending evaluation
(def jobs (agent []))
根据这些定义,我将拥有一个java线程池,每个线程将从jobs代理请求一个作业(并等待该请求得到满足)。然后它将运行计算,生成解决方案和可能的解决方案的列表。最后,它会将解决方案发送给解决方案代理,并将可能的解决方案发送给作业代理

在这种情况下,使用代理和线程的组合是最惯用的方式吗?我甚至可以按照我提议的方式从工作队列中获取数据吗


或者我的作业应该是java.util.concurrent.LinkedBlockingQueue,如中所述?

您使用代理和线程的方法似乎非常接近(我认为是)惯用的clojure


为了使它更像clojure,我唯一要做的修改是使用
pmap
迭代存储在代理中的队列。使用pmap而不是您自己的线程池将节省您管理线程池的工作量,因为pmap已经使用clojure的线程池,该线程池已针对当前处理器数正确初始化。它还可以帮助您利用序列分块(这可能会有所帮助)

您可以通过以下方法完成此操作:

  • 重复应用(提供集合中所有元素的并行处理)
  • pmap中使用的函数返回元素列表。可以是零个、一个或多个元素,这些元素将在下一次迭代中处理
  • 结果被重新组合为
  • 您可以根据需要多次重复处理列表,可能会将结果存储在atom中
示例代码可以如下所示

(def jobs (atom '(1 10 100)))

(defn process-element [value]
  (if (< (rand) 0.8)
    [(inc value)]
    []))

(defn do-processing []
  (swap! jobs 
         (fn [job-list] (apply concat (pmap process-element job-list)))))

(while (seq @jobs)
  (prn @jobs)
  (do-processing))

请注意,您需要小心一点,以确保您的算法终止!在本例中,元素随时间逐渐消失可以保证这一点,但如果搜索空间在增长,则可能需要应用时间限制,而不仅仅是使用通道。

您也可以使用通道。也许是这样的:

initial: '([] proposed-move)
accepted: '([move] proposed-response)
          '([move move] proposed-response)
(def jobs (chan))
(def solutions (chan))
(def accepted-solutions (atom (vector)))

(go (loop [job (<! jobs)]
      (when job
        (go (doseq [solution (process-job-into-solutions job)]
              (>! solutions)))
        (recur (<! jobs)))))

(go (loop [solution (<! solutions)]
      (when (acceptable? solution)
        (swap! accepted-solutions conj solution)
        (doseq [new-job (generate-new-jobs solution)]
          (>! jobs))
        (recur (<! solutions)))))

(>!! jobs initial-job)
(def作业(chan))
(def解决方案(chan))
(def接受的溶液(原子(向量)))
(go(循环[作业(!解决方案)))
(重复出现(!工作))
(重复(!!作业初始作业)

或者,可能是一系列的未来而不是线程池?这看起来像是一个非常有状态的实现。我建议以一种更实用的方式来实现它,并依靠核心函数来解决并发问题。这是一个图形搜索问题,而不是clojure问题;你正在掩盖最重要的部分。一旦你决定了关于搜索算法、启发式等,然后回来询问如何在clojure中实现它。Paul Lam在上面评论了“更具功能的实现”之后,我开始考虑递归使用pmap和利用懒散。我总是有一个深度截止,所以我知道我永远不会超过堆栈。我喜欢这个解决方案和你的解决方案。