Parallel processing 如何使用地点编写平行地图?

Parallel processing 如何使用地点编写平行地图?,parallel-processing,racket,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 (ch

我想在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中上下文外使用的标识符

我所看到的所有示例都显示了一种设计模式,即提供一个没有参数的主函数,该函数用于实例化其他位置,但使用起来非常麻烦,因此我正积极尝试避免它。这可能吗

注意:我还尝试使用futures制作一个平行地图。不幸的是,对于我所有的测试,它实际上比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)))

我以前使用过places,但从未将函数作为参数传递给place。我得到了以下使用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)

正如我所说的,粗鲁。欢迎所有建议

我以前使用过place,但从未将函数作为参数传递给place。我得到了以下使用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)

正如我所说的,粗鲁。欢迎所有建议

我在不稳定中看到了openplace,它将错误更改为ch未绑定。我在不稳定中看到了openplace,它将错误更改为ch未绑定。这看起来是一个非常有用的示例。我注意到的第一件事是2是最后一件。为什么呢?另外,我看到您正在传递一个符号作为参数,而不是函数。我认为函数本身不能作为消息传递?(当然,我尝试做的第一件事是在repl中定义fib,然后尝试调用其上的并行映射,导致一个错误,称fib未定义)。事实上,places似乎无法将函数作为消息接收,和往常一样,Racket给出了一个非常明显的错误。结果的顺序是不可预测的,因为计算是并行进行的。如果运行该程序几次,可能会得到不同的结果。如果你想以一定的顺序得到结果,你必须对工作单进行编号,并将结果与订单信息一起返回(并相应地进行组合)。这看起来是一个非常有用的例子。我注意到的第一件事是2是最后一件。为什么呢?另外,我看到您正在传递一个符号作为参数,而不是函数。我认为函数本身不能作为消息传递?(当然,我尝试做的第一件事是在repl中定义fib,然后尝试调用其上的并行映射,导致一个错误,称fib未定义)。事实上,places似乎无法将函数作为消息接收,和往常一样,Racket给出了一个非常明显的错误。结果的顺序是不可预测的,因为计算是并行进行的。如果运行该程序几次,可能会得到不同的结果。如果你想以一定的顺序得到结果,你必须对工作单进行编号,并将结果与订单信息一起返回(并相应地进行组合)。