如何使用Places编写并行映射?

时间:2013-09-28 20:03:08

标签: parallel-processing racket

我想在Racket中实现并行映射功能。地方似乎是正确的建设,但它们对我来说是一个未知的领域。我认为代码看起来应如下所示。

#lang racket

; return xs split into n sublists
(define (chunk-into n xs)
  (define N (length xs))
  (cond [(= 1 n) (list xs)]
        [(> n N) 
         (cons empty 
               (chunk-into (sub1 n) xs))]
        [else
         (define m (ceiling (/ N n)))
         (cons (take xs m) 
               (chunk-into (sub1 n) (drop xs m)))]))

(module+ test
  (check-equal? (length (chunk-into 4 (range 5))) 4)
  (check-equal? (length (chunk-into 2 (range 5))) 2))

(define (parallel-map f xs)
  (define n-cores (processor-count))
  (define xs* (chunk-into n-cores xs))
  (define ps 
    (for/list ([i n-cores])
      (place ch
             (place-channel-put 
              ch
              (map f
               (place-channel-get ch))))))
  (apply append (map place-channel-put ps xs*)))

这给出了错误:

  

f:在上下文中使用的标识符:f

我见过的所有示例都显示了一个设计模式,即提供一个没有参数的主函数,这些参数以某种方式用于实例化其他地方,但这样做真的很麻烦,所以我正在积极地试图避免它。这可能吗?

注意:我还尝试使用期货制作并行图。不幸的是,对于我的所有测试,它实际上比map慢(我尝试使用fib的递归过程版本进行测试),但是在这里,如果你有任何建议让它更快。

(define (parallel-map f xs)
  (define xs** (chunk-into (processor-count) xs))
  (define fs (map (λ (xs*) (future (thunk (map f xs*)))) xs**))
  (apply append (map touch fs)))

1 个答案:

答案 0 :(得分:1)

我之前使用过场景,但从未将函数作为参数传递给某个地方。我能够提出以下,相当狡猾的代码,它使用eval:

#!/usr/bin/env racket
#lang racket

(define (worker pch) 
  (define my-id (place-channel-get pch)) ; get worker id
  (define wch-w (place-channel-get pch)) ; get work channel (shared between controller and all workers) - worker side
  (define f     (place-channel-get pch)) ; get function
  (define ns    (make-base-namespace))   ; for eval
  (let loop ()
    (define n (place-channel-get wch-w)) ; get work order
    (let ((res (eval `(,f ,n) ns)))      ; need to use eval here !!
      (eprintf "~a says ~a\n" my-id res)
      (place-channel-put wch-w  res)     ; put response
      (loop))))                          ; loop forever

(define (parallel-map f xs)  
  (define l (length xs))
  (define-values (wch-c wch-w) (place-channel))    ; create channel (2 endpoints) for work dispatch (a.k.a. shared queue)
  (for ((i (in-range (processor-count))))
    (define p (place pch (worker pch)))            ; create place
    (place-channel-put p (format "worker_~a" i))   ; give worker id
    (place-channel-put p wch-w)                    ; give response channel
    (place-channel-put p f))                       ; give function
  (for ((n xs))
    (place-channel-put wch-c n))                   ; create work orders
  (let loop ((i 0) (res '()))                      ; response loop
    (if (= i l)
        (reverse res)
        (let ((response (sync/timeout 10 wch-c)))  ; get answer with timeout (place-channel-get blocks!)
          (loop 
           (+ i 1) 
           (if response (cons response res) res))))))

(module+ main 
  (displayln (parallel-map 'add1 (range 10))))

在控制台中运行,例如:

worker_1 says 1
worker_1 says 3
worker_1 says 4
worker_1 says 5
worker_1 says 6
worker_1 says 7
worker_1 says 8
worker_1 says 9
worker_1 says 10
worker_0 says 2
(1 3 4 5 6 7 8 9 10 2)

正如我所说,狡猾。欢迎所有建议!