期货以某种方式比代理商慢?

时间:2014-09-16 17:20:50

标签: clojure

以下代码基本上只允许您并行执行类似(function(range n))的内容。

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

例如,可以使用10个代理找到0到10000之间的素数。

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

与期货相同。

现在的问题是,期货的解决方案并没有更多的期货运行。例如:

; 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"

为什么呢?我做错了什么(可能是Clojure的新手,只是玩弄东西^^)?因为我认为期货在这种情况下实际上是首选。

来源:

(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)))))

1 个答案:

答案 0 :(得分:5)

由于forexperiment-with-futures内部产生了一个懒惰的序列,你会被绊倒。特别是这段代码:

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

不会立即创造所有期货;它返回一个惰性序列,在序列内容实现之前不会创建未来。实现延迟序列的代码是:

(vec (flatten (map deref futures)))

在这里,map返回一个懒惰的未解除的未来结果序列,由懒惰的未来序列支持。当vec消耗map生成的序列的结果时,每个新的未来都不会提交进行处理,直到前一个完成。

要进行并行处理,您不需要懒惰地创建期货。尝试将for循环包裹在doall内创建期货的位置。

您看到代理改进的原因是在收集代理结果之前立即调用(apply await agents)。您的start-agents函数也会返回一个惰性序列,并且实际上并不会调度代理操作。 apply的实现细节是它完全实现了传递给它的小序列(大约20项左右)。将agents传递给apply的副作用是序列已实现,并且所有代理操作在传递到await之前都会被调度。