Sebastian
Sebastian

Reputation: 2786

pmap and thread count

user=> (.. Runtime getRuntime availableProcessors)
2

And evaluating this example: http://clojuredocs.org/clojure_core/clojure.core/pmap#example_684 I get

user=> (time (doall (map long-running-job (range 4)))) 
"Elapsed time: 12000.621 msecs"
(10 11 12 13)
user=> (time (doall (pmap long-running-job (range 5))))
"Elapsed time: 3000.454 msecs"
(10 11 12 13 14)
user=> (time (doall (pmap long-running-job (range 32))))
"Elapsed time: 3014.969 msecs"
(10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 3839 40 41)
user=> (time (doall (pmap long-running-job (range 33))))
"Elapsed time: 6001.526 msecs"
(10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42)

I wonder why I have to pass 33 to wait 33 sec. for result. pmap create 2 (available processors) + 2 threads, yes? I suppose that when pass (range 5) it will be executed in 6 sec. Why it is different?

Upvotes: 4

Views: 1185

Answers (1)

Michał Marczyk
Michał Marczyk

Reputation: 84331

Actually pmap does not obey the "processors + 2" limit. That's a result of the ways in which the regular map and the future macro work:

  1. future uses a cached thread pool which has no size limit;

  2. map produces a chunked sequence, that is, one which is always forced 32 elements at a time, even if only a handful at the beginning of a chunk are actually consumed by the caller.

The ultimate result is that futures in pmap are launched in parallel in blocks of 32.

Note that this is not in violation of the contract specified in pmap's docstring. The code, on the other hand, might lead one to believe that it was intended that the "processors + 2" limit be respected -- as it would if map was written naively. In fact, pmap might well predate the move to chunked seqs, although I'm not really sure, it's been a while.

Upvotes: 9

Related Questions