Common Lisp并行采样

3

假设我想从某个概率分布中抽取样本。在下面的情况下,我抽取了一些在0到1之间均匀分布的随机变量,共进行了10000次。我不关心向量中随机样本的顺序,毕竟它们是随机的。

(setf my-vec (make-sequence 'vector 10000 :initial-element 0))
(loop :for i :from 0 :to 9999 :do
   (setf (svref my-vec i) (random 1.0)))

我有一台多核心机器,我想要并行实现上述代码。(例如,假设我有4个内核,在一个内核中采样2500次,最后将所有的样本追加到一个单一的向量中。之前我曾在这里询问过有关Common Lisp并行编程的问题。这里。假设我是CL和编程的新手,我应该如何解决这个问题?我不需要高级的并行化特性,我只想将采样的计算负载均衡分配到机器内核中。如果您能指出一些可供并行化使用的步骤或一些在线教程的信息,那将非常好。非常感谢您提前的帮助。
1个回答

5
你需要一个支持多核的通用Lisp实现。例如CCL、LispWorks,在某些平台上(如果我没记错的话)还有SBCL。
下面是使用LispWorks 6.1及其多进程功能的简单示例。 它使用一种称为barrier的结构,进程将等待直到足够的进程到达。 在这里,它意味着足够的线程已完成了它们的向量初始化。
启动线程的典型函数是PROCESS-RUN-FUNCTION
(defun make-random-vector (&key (size 10000) (n-threads 4))
  (let ((vector  (make-sequence 'vector size :initial-element 0))
        (barrier (mp:make-barrier (1+ n-threads)))
        (delta   (truncate size n-threads)))
    (loop for i below n-threads
          do (mp:process-run-function
              "init"
              nil
              (lambda (barrier vector start end)
                (loop for i from start below end do
                      (setf (svref vector i) (random 1.0)))
                (mp:barrier-wait barrier :pass-through t))
              barrier
              vector
              (* i delta)
              (+ delta (* i delta))))
    (mp:barrier-wait barrier)
    vector))

1
这是一个很好的例子。问题:每个线程都在写入同一个数组,是否会有任何减速?如果为每个线程创建单独的数组,然后在最后合并,速度会更快吗? - Clayton Stanley
1
@claytontstanley:绝对有道理,值得尝试。我考虑过这个,但我不想让示例代码变得太复杂。将工作分区、为工作启动线程并使用屏障进行同步的基本思路已经在示例中出现了。 - Rainer Joswig
@RainerJoswig,我正在使用CCL。与LispWorks相比,它会有什么特定的劣势吗?在CCL中编写代码是否像上面的代码一样紧凑?非常感谢。 - jkt
@YBE:与LispWorks相比,CCL的主要劣势可能是它提供的多进程内置库支持较少,如我所知。 - Rainer Joswig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接