【发布时间】:2015-05-10 16:43:52
【问题描述】:
注意——这里是 Clojure 新手。
我预计发生次数计数器的 Clojure 实现会比 Python 快得多。但事实证明 Python 更快!对此有何解释?如何推断 Python 在哪里会更快,Clojure 在哪里会更快?
我将 CPython 2.7.8 和 Clojure 1.6.0 与 OpenJDK 64 位服务器 VM 1.7.0_75-b13 一起使用。
Python 代码:
from string import ascii_lowercase
import timeit
DATA = list(ascii_lowercase)*100000
def frequencies(items):
counter = {}
for item in items:
counter[item] = counter.setdefault(item, 0) + 1
return counter
print(timeit.timeit(lambda: frequencies(DATA), number=1))
输出:
0.528199911118
Clojure 代码:
(ns test
(:gen-class))
(defn -main
[& args]
(let
[data
(doall (apply concat
(repeat 100000 (map char (range (int \a) (+ (int \z) 1))))))]
(time (frequencies data))))
输出:
"Elapsed time: 861.668743 msecs"
更新 #1
我做了一些优化:
(ns test
(:gen-class))
(defn frequencies2
[coll]
(into {} (reduce (fn [^java.util.HashMap counts x]
(.put counts x
(inc (or (.get counts x) 0))) counts)
(java.util.HashMap. {}) coll)))
(defn -main
[& args]
(let
[data
(doall (apply concat
(repeat 10000 (map char (range (int \a) (inc (int \z)))))))]
(time (dotimes [_ 15] (frequencies data)))
(time (dotimes [_ 15] (frequencies2 data)))))
它输出:
"Elapsed time: 1524.498547 msecs"
"Elapsed time: 476.387626 msecs"
所以我补充两个问题:
- 为什么
clojure.coreimplementation 不使用类型提示? - 如何进一步优化性能?我可以为整数的哈希映射值添加类型提示吗?
【问题讨论】:
-
Clojure 代码在我的机器上更快,即使没有为 JIT 预热。
-
如果我没记错的话,我认为 Clojure 版本更相当于这个
reduce(lambda x, y: x + Counter(y), a, Counter())而不是你发布的那个。 -
@AshwiniChaudhary
frequencies完全实现 like that -
我正在使用带有 core 2 duo 的旧 Macbook。 Python 版本始终以大约 768 毫秒的速度出现,而 Clojure 的平均时间大约为 575 毫秒(倾向于在 ±20 毫秒左右跳跃)。很多事情可能会影响时间。你运行的是哪个版本的 Clojure(或 Python),你运行的是哪个版本的 JVM,等等……
-
您的更新版本在比旧版本小十倍的数据对象上调用频率。此外,您的
data计算可以缩短/显着加快到(let [ascii-lowercase (char-array "abcdefghijklmnopqrstuvwxyz")] (reduce into [] (repeat 100000 ascii-lowercase)))。 Don't use concat。 FWIW,使用frequencies的 100.000 版本在我使用 Oracle JDK 的机器上需要大约 554 毫秒,而 Python 版本需要 0.449 秒,所以它们在同一个球场上,这不是你所看到的。
标签: python performance clojure