以下代码基本上只允许您并行执行类似(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)))))
答案 0 :(得分:5)
由于for
在experiment-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
之前都会被调度。