65.9K
CodeProject 正在变化。 阅读更多。
Home

比较 Ruby 和 C# 的性能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (7投票s)

2012年11月8日

CPOL

3分钟阅读

viewsIcon

55872

Ruby 性能与 C# 的快速测试

引言

我正在学习 Ruby 和 Ruby on Rails,我想快速比较一下 Ruby 和 C#,我知道 C# 会比 Ruby 表现更好,但我希望了解差距有多大。 这个网站表明 Ruby 平均慢 25 倍,但我希望亲自看看。 结果,Ashraff Ali Wahab 几天前发表了一篇文章C# 中埃拉托斯特尼/孙达拉姆/阿特金筛法的实现,我认为这是一种快速编写测试的方法。

这显然不是最终结论——这有点像在代码级别比较苹果和橙子,尤其是因为我尝试利用 Ruby 的语法达到我目前的理解水平。 此外,我还决定尝试IronRuby,但由于程序未能完成,测试没有得出结论。

源代码

C#

有关 C# 源代码,请参考 Ashraff Ali Wahab 的文章

Ruby

蛮力算法

def BruteForce(topCandidate)
  totalCount = 1
  isPrime = true

  3.step(topCandidate, 2) do |i|
    j=3

    while j*j <= i && isPrime
      isPrime = false if i%j==0
      j += 2
    end

    isPrime ? totalCount += 1 : isPrime = true
  end

totalCount
end

埃拉托斯特尼筛法

def SieveOfEratosthenes(topCandidate)
  myBA1 = Array.new(topCandidate + 1) {true}
  myBA1[0] = myBA1[1] = false
  thisFactor = 2

  while thisFactor * thisFactor <= topCandidate do
    mark = thisFactor + thisFactor
    mark.step(topCandidate+1, thisFactor) {|n| myBA1[n] = false}

    thisFactor += 1

    while !myBA1[thisFactor] do
      thisFactor += 1
    end

  end

  myBA1.count(true)
end

孙达拉姆筛法

def SieveOfSundaram(topCandidate)
  k = topCandidate / 2
  myBA1 = Array.new(k + 1) {true}
  myBA1[0] = myBA1[k] = false

  for i in 1..k do
    denominator = (i << 1) + 1
    maxVal = (k - i) / denominator
    i.step(maxVal+1, 1) {|n| myBA1[i + n * denominator] = false}

    # this version takes .20 seconds longer to run 1M iterations!
    # for n in i..maxVal+1 do
      # myBA1[i + n * denominator] = false
    # end
  end

myBA1.count(true) + 1
end

“Main”(主函数)

def main
  max = 1000000
  startTime = Time.now()
  primes = BruteForce(max)
  endTime = Time.now()
  elapsed = endTime - startTime
  printf("Elapsed time for Brute Force : %f Primes = %d\n", elapsed, primes)

  startTime = Time.now()
  primes = SieveOfEratosthenes(max)
  endTime = Time.now()
  elapsed = endTime - startTime
  printf("Elapsed time for Sieve of Eratosthenes: %f Primes = %d\n", elapsed, primes)

  startTime = Time.now()
  primes = SieveOfSundaram(max)
  endTime = Time.now()
  elapsed = endTime - startTime
  printf("Elapsed time for Sieve of Sundaram : %f Primes = %d\n", elapsed, primes)
end

结果

你可以从这些截图中看到

Ruby

  • 对于蛮力算法慢了大约 5 倍
  • 对于埃拉托斯特尼和孙达拉姆算法慢了大约 19 倍

对我来说,这基本上与我在简介中提到的 shootout 网站一致。

遗憾的是,IronRuby 程序没有完成

死在这一行

myBA1.count(true)

但是蛮力算法始终慢了近两倍。

在 Virtual Box 上运行

我还在 Virtual Box(2GB 内存,3 个处理器)上运行 Ubuntu,对结果感到满意

只慢了大约 3 倍!

结论

虽然不是最终结论,但这是一个有用的练习。 请特别注意注释掉的 Ruby 代码

    i.step(maxVal+1, 1) {|n| myBA1[i + n * denominator] = false}

    # this version takes .20 seconds longer to run 1M iterations!
    # for n in i..maxVal+1 do
      # myBA1[i + n * denominator] = false
    # end

“for”循环版本花费的时间几乎长 50%! 这是一个重要且有价值的发现,并且本质上是有道理的——step函数是一个库实现(因此我认为是编译过的),而我猜想for循环一直在被解释。 尽管如此,这是一个显着的差异,特别是考虑到块{|n| myBA1[i + n * denominator] = false}理论上是作为函数调用来实现的。

此外,IronRuby 代码失败令人失望。 我希望如此“简单”的东西不会出现问题。

最后,请不要将此视为对 Ruby 的贬低! 这是一种了不起的语言,对于许多用途来说,性能并不是最重要的——与数据库的交互和网络延迟(如果你考虑 Ruby on Rails)通常比语言性能对性能感知的影响更大。

此外,似乎有一些可用的编译器,例如Rubinius以及The Ludicrous JIT Compiler。 前者看起来太复杂而无法尝试,后者 Ludicrous,我确实尝试过,但安装没有成功。 鉴于创建者声称“虽然仍处于实验阶段,但其性能大致与 YARV 相当”,鉴于:“Ruby 1.9 中可能最令人兴奋和可见的变化是为 Ruby 添加了字节码解释器。 YARV(Yet Another Ruby VM)解释器已集成到 Ruby 项目中,取代了 Matz 创建的解释器(又名 MRI,Matz 的 Ruby 解释器)。” (阅读这里)。

© . All rights reserved.