使用Clojure期货计算长期金额

时间:2014-01-12 14:09:20

标签: concurrency clojure future

运行此代码:

(ns playfield.core)

(defn sum
  [start end]
  (reduce + (range start end)))

(def size 1e8)

(defn -main
  [& args]
  (println (time (sum 0 size)))
  (println (time (let [left (future (sum 0 (/ size 2)))
                       right (future (sum (/ size 2) size))]
                   (+ @left @right)))))

给我这个输出:

"Elapsed time: 2742.185 msecs"
4999999950000000
"Elapsed time: 2605.541 msecs"
4.99999995E15

我期待第二个占用大约一半的时间,因为我在两个线程上分配计算。我做错了什么?

1 个答案:

答案 0 :(得分:1)

我稍微修改了您的示例(在(shutdown-agents)末尾添加-main)并在两台计算机上运行(lein run -m playfield.core):

Retina Macbook Pro,2012年中期

  • 2.3 GHz Intel Core i7
  • 16 GB RAM
  • Java(TM)SE运行时环境(版本1.7.0_45-b18)

结果:

serial:   2678.034 msecs
parallel: 1943.153 msecs
Parallel takes 72.3% of baseline.

请注意,这些结果与我原来的评论不同。该数据来自REPL。

联想Thinkstation S20

  • 3.07GHz Intel Xeon W3550
  • 8 GB RAM
  • Java(TM)SE运行时环境(版本1.7.0_45-b18)

结果:

Serial:   12390.296313 msecs
Parallel:  6856.656525 msecs
Parallel takes 55.3% of baseline.

我可以想到在基准测试时你可能遇到的两个问题:

  1. 该机器没有多个内核/ Java仅限于一个内核/否则将加载内核。
  2. 对JVM进行基准测试非常棘手。通常,建议使用criterium代替。但是,我上面的数字只是使用time生成的,所以我不确定它会在这里发挥作用。
  3. 修改

    我有更多的想法:

    正如@lgrapenthin所提到的,JVM选项会影响时间。例如,lein使用以下两个选项improve startup time-XX:+TieredCompilation -XX:TieredStopAtLevel=1。对于这种情况,改变这种情况有明显的区别:

    $ LEIN_JVM_OPTS="" lein run -m 'speed.core'
    Serial:   2496.435288 msecs
    Parallel: 2045.084565 msecs
    Parallel takes 81.9% of baseline. 
    

    来自@Giuseppe的评论指出正在积极使用4个核心(我认为这意味着充分利用)。也许JVM具有很高的内存压力,并且CPU使用率是垃圾收集器疯狂地工作以使一些内存可用。然而,我无法在本地重现这一点。