44441 # Futures somehow slower then agents?

The following code does essentially just let you execute something like (function (range n)) in parallel.

```(experiment-with-agents 10000 10 #(filter prime? %)) ```

This for example finds the prime numbers between 0 and 10000 with 10 agents.

```(experiment-with-futures 10000 10 #(filter prime? %)) ```

Same just with futures.

Now the problem is that the solution with futures doesn't run faster with more futures. Example:

```; Futures (time (experiment-with-futures 10000 1 #(filter prime? %))) "Elapsed time: 33417.524634 msecs" (time (experiment-with-futures 10000 10 #(filter prime? %))) "Elapsed time: 33891.495702 msecs" ; Agents (time (experiment-with-agents 10000 1 #(filter prime? %))) "Elapsed time: 33048.80492 msecs" (time (experiment-with-agents 10000 10 #(filter prime? %))) "Elapsed time: 9211.864133 msecs" ```

Why? Did I do something wrong (probably, new to Clojure and just playing around with stuff^^)? Because I thought that futures are actually prefered in that scenario.

Source:

```(defn setup-agents [coll-size num-agents] (let [step (/ coll-size num-agents) parts (partition step (range coll-size)) agents (for [_ (range num-agents)] (agent []) ) vect (map #(into [] [%1 %2]) agents parts)] (vec vect))) (defn start-agents [coll f] (for [[agent part] coll] (send agent into (f part)))) (defn results [agents] (apply await agents) (vec (flatten (map deref agents)))) (defn experiment-with-agents [coll-size num-agents f] (-> (setup-agents coll-size num-agents) (start-agents f) (results))) (defn experiment-with-futures [coll-size num-futures f] (let [step (/ coll-size num-futures) parts (partition step (range coll-size)) futures (for [index (range num-futures)] (future (f (nth parts index))))] (vec (flatten (map deref futures))))) ```

You're getting tripped up by the fact that `for` produces a lazy sequence inside of `experiment-with-futures`. In particular, this piece of code:

```(for [index (range num-futures)] (future (f (nth parts index)))) ```

does not immediately create all of the futures; it returns a lazy sequence that will not create the futures until the contents of the sequence are realized. The code that realizes the lazy sequence is:

```(vec (flatten (map deref futures))) ```

Here, `map` returns a lazy sequence of the dereferenced future results, backed by the lazy sequence of futures. As `vec` consumes results from the sequence produced by `map`, each new future is not submitted for processing until the previous one completes.

To get parallel processing, you need to not create the futures lazily. Try wrapping the `for` loop where you create the futures inside a `doall`.

The reason you're seeing an improvement with agents is the call to `(apply await agents)` immediately before you gather the agent results. Your `start-agents` function also returns a lazy sequence and does not actually dispatch the agent actions. An implementation detail of `apply` is that it completely realizes small sequences (under 20 items or so) passed to it. A side effect of passing `agents` to `apply` is that the sequence is realized and all agent actions are dispatched before it is handed off to `await`.