[racket] parallelism
On May 11, 2011, at 3:23 PM, Robby Findler wrote:
> You might try futures. Do read the guide first, of course.
I've tried some simple experiments.
The function in question iterates over every pixel of an image being constructed:
(for* ((y (in-range 0 height))
(x (in-range 0 width)))
; set the (x,y) pixel in the bitmap to be the result of a function call on x and y
)
I wrote another version that parallelizes the rows:
(touch-all (for/list ((y (in-range 0 height)))
(future (lambda () (for ((x (in-range 0 width)))
; set the (x,y) pixel as above
))))
(define (touch-all futures)
(for ((f futures)) (touch f)))
This version occasionally crashes DrRacket, but usually runs in about twice the time of the non-futures version.
I wrote another version that parallelizes the columns:
(for ((y (in-range 0 height)))
(touch-all (for/list ((x (in-range 0 width)))
(future (lambda ()
; set the (x,y) pixel as above
))))))
I don't think I've ever gotten this version to run without crashing DrRacket, so I have no timing data.
I wrote another version that parallelizes both rows and columns:
(touch-all (for*/list ((y (in-range 0 height))
(x (in-range 0 width)))
(future (lambda ()
; set the (x,y) pixel as above
))))
This ran once without crashing, but it produced a wrong answer, and I didn't get the timing data. Every other time I've tried it, DrRacket has crashed.
The likelihood of crashing seems to be lower if width and height are smaller.
I then tried some simpler, smaller, non-image examples:
(define nums (build-list 1000 (lambda (x) x))
(time (touch-all (map (lambda (x) (future (lambda () (sqrt x)))) nums)))
vs.
(time (map sqrt nums))
I can't tell how much slower the former is than the latter, because I've never gotten the latter to exceed 0 ms :-)
But at least the futures version has CPU time > real time, which suggests there's some parallelization going on.
So I figured "maybe you're not supposed to use more futures than you have processors."
I'm running on a machine with 4 parallel processors, according to (processor-count).
So I tried something with only 3 futures:
(time (touch-all (map (lambda (x) (future (lambda () (map (lambda (y) (* x y)) nums)))) '(1 2 3)))
as compared with a non-futures version
(time (map (lambda (x) (map (lambda (y) (* x y)) nums)) '(1 2 3)))
The futures version takes about twice as long as the non-futures version. But again, CPU time > real time, which suggests some parallelization.
I suspect that futures would be more useful if each of the tasks were bigger; I should try some more experiments with more complex tasks.
Stephen Bloch
sbloch at adelphi.edu