Multithreading Guile方案并行表单加速

Multithreading Guile方案并行表单加速,multithreading,parallel-processing,scheme,guile,Multithreading,Parallel Processing,Scheme,Guile,我正在试验Guile方案的并行形式,我有以下代码: (use-modules (srfi srfi-1) (ice-9 pretty-print) (ice-9 receive)) (define (busy-work limit) (if (> limit 0) (begin (sqrt (+ (expt limit limit) 1)) (busy-work (- limit 1)))

我正在试验Guile方案的并行形式,我有以下代码:

(use-modules (srfi srfi-1)
             (ice-9 pretty-print)
             (ice-9 receive))

(define (busy-work limit)
  (if (> limit 0)
      (begin (sqrt (+ (expt limit limit) 1))
             (busy-work (- limit 1)))
      'done))

(define (busy-work-2 lst)
  (cond [(null? lst) 'done]
        [else
         (expt (car lst) (car lst))
         (busy-work-2 (cdr lst))]))

(define (time thunk)
  (define starting-time (current-time))
  (define res (thunk))
  (define ending-time (current-time))
  (display "elapsed time: ")
  (display (- ending-time starting-time))
  (display "s")
  (newline)
  res)


(define (partition-4 numbers)
  (define (loop numbers rc0 rc1 rc2 rc3)
    (cond [(null? numbers) (list (reverse rc0)
                                 (reverse rc1)
                                 (reverse rc2)
                                 (reverse rc3))]
          [else
           (let* ([number (car numbers)]
                  [residue (remainder number 4)])
             (cond [(= residue 0) (loop (cdr numbers)
                                        (cons number rc0)
                                        rc1
                                        rc2
                                        rc3)]
                   [(= residue 1) (loop (cdr numbers)
                                        rc0
                                        (cons number rc1)
                                        rc2
                                        rc3)]
                   [(= residue 2) (loop (cdr numbers)
                                        rc0
                                        rc1
                                        (cons number rc2)
                                        rc3)]
                   [(= residue 3) (loop (cdr numbers)
                                        rc0
                                        rc1
                                        rc2
                                        (cons number rc3))]))]))
  (loop numbers '() '() '() '()))
(或在我的实验库中)

据我所知,这两个程序
busy-work
busy-work-2
都是纯数字运算,有数字列表,没有计算依赖于另一个。我知道时间测量可能不完全准确

然而,我始终没有从使用更多线程(核心,正如我在我的CPU指示器中看到的核心使用情况)中获得预期的加速

下面是一些示例,我希望2个线程完成任务的速度是1个内核的两倍,4个内核完成任务的速度是2个内核的两倍。好吧,至少或多或少,因为我正在以某种方式拆分列表,这种方式应该或多或少地平均分配工作

使用4核和
并行
这在我的机器上大约10秒后完成。有时9,有时10

使用使用4个线程(核心)的
par map
这在我的机器上大约10秒后完成。有时9,有时10。就像使用
并行
一样

使用带有4个线程的
n-par-map
(在我的机器上) 还有10秒。这里的手册()说:

与上述函数不同,下面描述的函数将多个线程作为参数。由于指定的线程数可能与当前处理器计数返回的可用CPU内核数不同(请参阅进程),这使得它们本质上不可移植。此外,这些函数在被调用时创建指定数量的线程,并在完成时终止它们,这使得它们非常昂贵

因此,应该避免使用它们

虽然我发现这个解释没有100%的意义(为什么
n-par-map
不使用与
parallel
相同的预创建线程,如果这些线程足够多的话?比如我的机器上的
4
),但我没有看到任何大的开销,我再次看到它大约在10秒内完成。我的猜测是,线程创建所花费的时间很短,与所有的数字运算相比,它根本没有被注意到

使用带有2个线程(核心)的
n-par-map
期望值:可能在20秒内完成

结果:此操作在12秒内完成

现在我当然在想:“在运行4核时一定会有一些巨大的开销!”


问:但当我做纯粹的数字运算而没有任何结果的相互依赖性时,这种开销从何而来?它是否使用了一些共享内存,从而导致内存访问成为瓶颈?

您可能正在使用一台具有两个超线程物理内核的机器,因此报告了4个CPU。它表明这种工作负载不适合超线程


我在一台有两个超线程物理内核的机器上得到了类似的结果。然而,对于一台具有4个物理内核的机器,我使用所有4个内核获得9秒,仅使用2个内核获得16秒,这更符合您的预期。

哦,这是真的,我正在使用这样的机器!9s与16s的4个实际内核似乎也更合理。我在想,可能缓存不够,内核在某个时候使用相同的缓存,这使得它们等待内存来进行计算。我想再等一会儿,如果没有其他事情发生,就接受你的回答。
(let ([residue-classes (partition-4 (iota 30000))])
  (time
   (lambda ()
     (parallel (busy-work-2 (car residue-classes))
               (busy-work-2 (cadr residue-classes))
               (busy-work-2 (caddr residue-classes))
               (busy-work-2 (cadddr residue-classes))))))
(let ([residue-classes (partition-4 (iota 30000))])
  (time
   (lambda ()
     (par-map busy-work-2
              residue-classes))))
(let ([residue-classes (partition-4 (iota 30000))])
  (time
   (lambda ()
     (n-par-map (current-processor-count)
                busy-work-2
                residue-classes))))
(let ([residue-classes (partition-4 (iota 30000))])
  (time
   (lambda ()
     (n-par-map 2
                busy-work-2
                residue-classes))))