比较 Ruby 和 C# 的性能






4.75/5 (7投票s)
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 解释器)。” (阅读这里)。