python的reduce实现会产生什么开销?

2024-05-29 04:22:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些python脚本花费的时间比我预期的要长,所以我开始调查并发现python的性能有一些令人惊讶的地方。大多数情况下,它似乎围绕着reduce展开,但我不明白为什么。在

为了进行实验,我编写了以下两个模块:

py.py

from functools import reduce

def mysum(n):
    return reduce(lambda acc, x: acc + x, range(n + 1))

n = int(1e8)
print(mysum(n))

以及

clj.clj

^{pr2}$

我用time比较了他们的表现:

➜  ~ time python py.py
5000000050000000
python py.py  21.90s user 0.41s system 95% cpu 23.344 total
➜  ~ time lumo clj.clj
5000000050000000
lumo clj.clj  2.44s user 0.13s system 102% cpu 2.519 total

python的执行速度似乎比clojure实现慢10倍以上。但这与我的预期正好相反。在

即使在使用JVM运行clj文件时(这会导致大量的启动成本),python也会被远远击败:

➜  ~ time clj clj.clj
5000000050000000
clj clj.clj  6.01s user 0.72s system 153% cpu 4.394 total

为什么python的reduce在这里这么慢?我做错什么了吗?在


Tags: py脚本reducetime时间cpu性能system
2条回答

我记得,range生成一个列表,而xrange生成iterable。尽管如此,我试着更换它,但没用。所以,是的,这里的关键问题似乎与口译员的本性有关。 顺便说一下,这个很快就好了- 总和(X范围(10000001))

您的python代码正在被解释,而Clojure代码是由HotSpot编译器在JVM上编译的。这是JVM上的一大优势,也是Python&Ruby在JVM上分别有Jython和JRuby端口的原因。在

简单求和在原生Java中甚至更快:下面是一些快速比较:

class Calc {
  public static long cumsum( long limit ) {
    long result = 0;
    for (long i=0; i<limit; i++) {
      result += i;
    }
    return result;
  }

(let [limit 1e8]
  (newline) (println :result-clj)
  (crit/quick-bench (reduce + (range limit)))

(newline) (println :result-java-cumsum)
(crit/quick-bench (Calc/cumsum limit)))

:result-clj             Execution time mean : 1777.600 ms
:result-java-cumsum     Execution time mean :   26.920399 ms

是的,这是66倍的加速。尝试将计数减少到1e6。在

^{pr2}$

另一个诀窍是Hotspot编译器通常可以识别1..N中的和并在代数公式中进行替换

sum(1..N) => N*(N+1)/2

根本没有循环!在

相关问题 更多 >

    热门问题