解释C,Clojure,Python,Ruby,Scala等的基准

问题:

声明

我知道人为的基准是邪恶的。他们只能在非常狭窄的情况下显示结果。我不认为一种语言比另一种语言更好,因为一些愚蠢的长凳。但是我不知道为什么结果是如此不同。请在底部查看我的问题。

数学基准描述

基准是简单的数学计算,找到不同于6的素数对(所谓的sexy primes
例如。 100以下的性感素材将是:(5 11) (7 13) (11 17) (13 19) (17 23) (23 29) (31 37) (37 43) (41 47) (47 53) (53 59) (61 67) (67 73) (73 79) (83 89) (97 103)

结果表

 In table: calculation time in seconds
运行:除了Factor之外的所有运行在VirtualBox(Debian unstable amd64 guest,Windows 7 x64主机)
CPU:AMD A4-3305M

  Sexy primes up to:        10k      20k      30k      100k               

  Bash                    58.00   200.00     [*1]      [*1]

  C                        0.20     0.65     1.42     15.00

  Clojure1.4               4.12     8.32    16.00    137.93

  Clojure1.4 (optimized)   0.95     1.82     2.30     16.00

  Factor                    n/a      n/a    15.00    180.00

  Python2.7                1.49     5.20    11.00       119     

  Ruby1.8                  5.10    18.32    40.48    377.00

  Ruby1.9.3                1.36     5.73    10.48    106.00

  Scala2.9.2               0.93     1.41     2.73     20.84

  Scala2.9.2 (optimized)   0.32     0.79     1.46     12.01

[* 1] – 我想要想要多少时间

代码列表

C:

int isprime(int x) {
  int i;
  for (i = 2; i < x; ++i)
    if (x%i == 0) return 0;
  return 1;
}

void findprimes(int m) {
  int i;
  for ( i = 11; i < m; ++i)
    if (isprime(i) &amp;&amp; isprime(i-6))
      printf("%d %d\n", i-6, i);
}

main() {
    findprimes(10*1000);
}
&#91;/code&#93;
红宝石:
&#91;code lang="python"&#93;
def is_prime?(n)
  (2...n).all?{|m| n%m != 0 }
end

def sexy_primes(x)
  (9..x).map do |i|
    &#91;i-6, i&#93;
  end.select do |j|
    j.all?{|j| is_prime? j}
  end
end

a = Time.now
p sexy_primes(10*1000)
b = Time.now
puts "#{(b-a)*1000} mils"
&#91;/code&#93;
斯卡拉:
&#91;code lang="python"&#93;
def isPrime(n: Int) =
  (2 until n) forall { n % _ != 0 }

def sexyPrimes(n: Int) = 
  (11 to n) map { i => List(i-6, i) } filter { _ forall(isPrime(_)) }

val a = System.currentTimeMillis()
println(sexyPrimes(100*1000))
val b = System.currentTimeMillis()
println((b-a).toString + " mils")

Scala对isPrime(与Clojure优化相同的想法)进行了验证:

import scala.annotation.tailrec

@tailrec // Not required, but will warn if optimization doesn't work
def isPrime(n: Int, i: Int = 2): Boolean = 
  if (i == n) true 
  else if (n % i != 0) isPrime(n, i + 1)
  else false

Clojure的:

(defn is-prime? [n]
  (every? #(> (mod n %) 0)
    (range 2 n)))

(defn sexy-primes [m]
  (for [x (range 11 (inc m))
        :let [z (list (- x 6) x)]
        :when (every? #(is-prime? %) z)]
      z))

(let [a (System/currentTimeMillis)]
  (println (sexy-primes (* 10 1000)))
  (let [b (System/currentTimeMillis)]
    (println (- b a) "mils")))

Clojure优化is-prime?

(defn ^:static is-prime? [^long n]
  (loop [i (long 2)] 
    (if (= (rem n i) 0)
      false
      (if (>= (inc i) n) true (recur (inc i))))))

蟒蛇

import time as time_

def is_prime(n):
  return all((n%j > 0) for j in xrange(2, n))

def primes_below(x):
  return [[j-6, j] for j in xrange(9, x+1) if is_prime(j) and is_prime(j-6)]

a = int(round(time_.time() * 1000))
print(primes_below(10*1000))
b = int(round(time_.time() * 1000))
print(str((b-a)) + " mils")

因子

MEMO:: prime? ( n -- ? )
n 1 - 2 [a,b] [ n swap mod 0 > ] all? ;

MEMO: sexyprimes ( n n -- r r )
[a,b] [ prime? ] filter [ 6 + ] map [ prime? ] filter dup [ 6 - ] map ;

5 10 1000 * sexyprimes . .

巴什(zsh中):

#!/usr/bin/zsh
function prime {
  for (( i = 2; i < $1; i++ )); do
    if &#91;&#91; $&#91;$1%i&#93; == 0 &#93;&#93;; then
      echo 1
      exit
    fi
  done
  echo 0
}

function sexy-primes {
  for (( i = 9; i <= $1; i++ )); do
    j=$&#91;i-6&#93;
    if &#91;&#91; $(prime $i) == 0 &amp;&amp; $(prime $j) == 0 &#93;&#93;; then
      echo $j $i
    fi
  done
}

sexy-primes 10000
&#91;/code&#93;
<h2>问题</h2>
<ol>
<li>为什么Scala如此之快?是因为<strong>静态打字</strong>吗?还是只是非常有效地使用JVM?</li>
<li> <s>Why such a huge difference between Ruby and Python? I thought these two are not somewhat totally different. Maybe my code is wrong. Please enlighten me! Thanks.</s> <strong>UPD</strong>是的,这是我的代码错误。 Python和Ruby 1.9是相当平等的。</li>
<li>Ruby版本之间的生产力真的令人印象深刻。</li>
<li>可以通过添加类型声明来优化Clojure代码吗?会有帮助吗</li>
</ol>

<h4>回答:</h4>
粗糙的答案:
<ol>
<li>Scala的静态类型很有帮助,这意味着它可以非常有效地使用JVM,而无需太多的额外工作。</li>
<li>我不完全相信Ruby / Python的区别,但我怀疑函数<code>is-prime?</code>中的<code>(2...n).all?</code>可能会在Ruby中得到很好的优化(编辑:听起来就是这样,请参阅Julian的答案更多详情...)</li>
<li>Ruby 1.9.3更好的优化了</li>
<li>Clojure代码当然可以加速很多!虽然默认情况下Clojure是动态的,但在许多情况下,您可以使用类型提示,原始数学等来接近Scala /纯Java速度。</li>
</ol>
Clojure代码中最重要的优化是在<code>is-prime?</code>中使用类型化的原始数学,如下所示:

(set! *unchecked-math* true) ;; at top of file to avoid using BigIntegers

(defn ^:static is-prime? [^long n]
  (loop [i (long 2)] 
    (if (zero? (mod n i))
      false
      (if (>= (inc i) n) true (recur (inc i))))))

有了这个改进,我得到Clojure在0.635秒内完成10k(即你的名单上第二快,击败了Scala)
 附:请注意,在某些情况下,您可以在基准测试中打印代码 - 这不是一个好主意,因为它会导致结果的扭曲,特别是如果第一次使用像print这样的函数会导致IO子系统的初始化或类似的事情!

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: Interpreting a benchmark in C, Clojure, Python, Ruby, Scala and others

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

+ 68 = 75