我如何基准(比较)Python与Clojure的性能?

ali*_*dry 2 python clojure python-3.x

我正在学习Clojure并且为了更好地处理我的进度,我决定开始用语言解决Project Euler问题(其中一些我已经用C++和Python解决了).问题1如下:

如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.

求出1000以下3或5的所有倍数的总和.

这是我第一次参加Clojure解决方案:

(defn main1
  ([n]
    (reduce +
      (filter
        #(or
          (= 0 (mod % 3))
          (= 0 (mod % 5)))
        (range n)))))
Run Code Online (Sandbox Code Playgroud)

然后我查看了我的Python版本的代码,如下所示:

import sys
import operator
from functools import reduce


def main(n=1000):
    """
    returns solution up to but excluding n
    """
    genexp = (num for num in range(1, n) if ((num % 3 == 0) or (num % 5 == 0)))
    total = reduce(operator.add, genexp)
    return total


if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(main(int(sys.argv[1])))
    else:
        print(main())
Run Code Online (Sandbox Code Playgroud)

忽略我在Python版本中添加的额外CLI-args内容,唯一的主要区别是我filter在Clojure中使用而不是生成器.我想我也可以filter在Python中使用过,但只是为了论证,我使我的Clojure代码更类似于Python代码:

(defn main2
  ([n]
    (reduce + (for [i (range n)
                  :let [div3 (= 0 (mod i 3))
                        div5 (= 0 (mod i 5))]
                  :when (or div3 div5)]
               i))))
Run Code Online (Sandbox Code Playgroud)

这让我思考 - 如何对这些函数进行基准测试以进行比较?对于Python,它很容易:

$ time python python/p0001.py 10000000
23333331666668

real    0m2.693s
user    0m2.660s
sys 0m0.018s

$ time python python/p0001.py 100000000
2333333316666668

real    0m26.494s
user    0m26.381s
sys 0m0.050s
Run Code Online (Sandbox Code Playgroud)

它会n=100,000,000在合理的时间内(30秒内)达到.如何为我的Clojure函数运行类似的测试?我想我必须在运行之前先编译Clojure代码.鉴于Python代码不是在这里进行JIT编译,这甚至是公平的比较吗?

另一方面,我的Clojure代码(两个版本)是如何惯用的?什么是代码样式的一些好建议?有类似pep8的风格指南吗?或者甚至是Clojure版本的pep20:"Python的禅宗"?

Ala*_*son 6

内置功能time适用于第一次切割:

(time (main1 100000000)) => 2333333316666668
"Elapsed time: 15824.041487 msecs"
Run Code Online (Sandbox Code Playgroud)

您还可以使用优秀的criterium图书馆

(ns xyz.core
  (:require [criterium.core :as cc] ))

(cc/quick-bench (main1 999))

Evaluation count : 3894 in 6 samples of 649 calls.
             Execution time mean : 154.680082 µs
    Execution time std-deviation : 750.591607 ns
   Execution time lower quantile : 153.982498 µs ( 2.5%)
   Execution time upper quantile : 155.870826 µs (97.5%)
                   Overhead used : 7.898724 ns

Found 1 outliers in 6 samples (16.6667 %)
    low-severe   1 (16.6667 %)
 Variance from outliers : 13.8889 % Variance is moderately inflated by outliers
Run Code Online (Sandbox Code Playgroud)

  • "预热"和冷运行时间之间100倍的运行时差异就是为什么你真的无法在没有仔细考虑的情况下在Clojure中获得有意义的基准测试.很好的答案. (3认同)