[racket] parallelism

From: Stephen Bloch (sbloch at adelphi.edu)
Date: Thu May 12 21:44:46 EDT 2011

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



Posted on the users mailing list.