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

Say*_*ras 2 clojure

以下代码基本上只允许您并行执行类似(function(range n))的操作.

(experiment-with-agents 10000 10 #(filter prime? %))
Run Code Online (Sandbox Code Playgroud)

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

(experiment-with-futures 10000 10 #(filter prime? %))
Run Code Online (Sandbox Code Playgroud)

与期货一样.

现在的问题是,期货的解决方案不会随着更多的期货而更快地运行.例:

; 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"
Run Code Online (Sandbox Code Playgroud)

为什么?我做错了什么(可能是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)))))
Run Code Online (Sandbox Code Playgroud)

Ale*_*lex 5

你会因为for产生一个懒惰的序列而被绊倒experiment-with-futures.特别是这段代码:

(for [index (range num-futures)] (future (f (nth parts index))))
Run Code Online (Sandbox Code Playgroud)

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

(vec (flatten (map deref futures)))
Run Code Online (Sandbox Code Playgroud)

在这里,map返回由滞后的未来序列支持的解除引用的未来结果的懒惰序列.由于vec消耗是由生成的序列产生的map,因此每个新的未来在前一个完成之前不会被提交进行处理.

要获得并行处理,您不需要懒惰地创建期货.尝试包装for你在a里面创建未来的循环doall.

您看到代理商有所改进的原因是(apply await agents)在您收集代理商结果之前立即致电.您的start-agents函数也返回一个惰性序列,并不实际调度代理操作.实现细节apply是它完全实现传递给它的小序列(不超过20项).传递的副作用是实现序列,并且在传递agentsapply所有代理动作之前调度它们await.