重写顺序执行的顺序代码

时间:2014-09-30 03:14:28

标签: parallel-processing refactoring lisp common-lisp

重写用于并行执行的常见lisp顺序代码的最佳惯用方法是什么?

有一些好的库,比如lparallel,可以帮助处理简单的案例。例如,如果我们在长列表中有一些mapcar,我们可以用lparallel:mapcar替换它,并且它在大多数情况下都可以完成工作。现在我进行了一些循环调用,获取了一些远程JSON API的结果并将其纳入列表:

(loop :for offset :from 0 :by 100
           :for result = (get-remote-data offset) 
           :until (null result) :nconc result)

如何替换它,并行调用get-remote-data而无需更改get-remote-data本身?有没有标准和惯用的方法?任何关于这个主题的好读也会有所帮助。感谢。

2 个答案:

答案 0 :(得分:4)

我已将chanl用于此类用例来设置消息队列。一世 启动 n 工作线程,进行远程调用并将其发送给 队列。聚合器从队列中获取结果 连接它们。

如果订单很重要,这可能不对。你也许也许 预定义在定义的单独填充的结果数组 工人的抵消。

编辑:为了获得未知数量的页面,您可以使用 原子偏移计数器和原子标志。工人线程(来自 固定池)然后检查标志,从计数器获得下一个偏移量, 进行远程调用,最后将结果发送到队列,或者, 如果结果为空,请关闭标志。如果标志被翻转掉 检查它的任何工作线程都会自行关闭。当工人 线程池是空的,你已经完成了。

答案 1 :(得分:2)

我使用lparallel创建了以下内容:

(defun get-datum (n)
     (sleep (random 2))
     (if (> n 1000)
         ()
         (list n)))

(defun get-data ()
  (let ((channel (lparallel:make-channel))
        results)
    (flet ((collect (item)
             (setq results (append item results))))

      ;; Ask lparallel to schedule the first 8 requests
      (loop for i from 0 to 70 by 10
            do (lparallel:submit-task channel #'get-datum i))

      ;; Schedule an additional request each time one returns
      ;; until we get a null result
      (loop for i from 80 by 10
            for result = (lparallel:receive-result channel)
            while result
            do (lparallel:submit-task channel #'get-datum i)
            (collect result))

      ;; wait for all outstanding requests
      (loop repeat 7
            do (collect (lparallel:receive-result channel)))

      results)))