你可能會覺得下面的圖表比較有意思,因為它是分別用三種程式設計語言(Ruby, Java, C/C++)寫的埃拉托色尼質數過濾演算法(譯註:Sieve of Eratosthenes)的效能分析圖,(本文的最後附有相應代碼)
好,很明顯Ruby是慢的,而且慢了大概有1.5個數量級(譯註:即約30倍)。這對於Ruby愛好者來說可不是個好訊息。不過換個角度看,呼!
Ruby與五、六年前的頂級電腦一樣快。還記得第一次在刻度不到一兆赫的機器上跑程式的神奇情景嗎...我們還為此興奮得直往山頂跑!
注意一下,這三條曲線是同樣形狀的,我們可以從上篇blog中瞭解到為何曲線會呈線性。最後要關注的是,Java的曲線以極其微小的優勢快於C++。你
可以抱怨那是因為沒有用gcc編譯器最佳化編譯的緣故(我用的是cygwin(譯註:gcc編譯器移植到windows的版本)),可是,如果現在還有任何
C++程式員還會嘲笑Java的效能的話,我勸你最好還是再重新掂量掂量吧。
而對於那些因為他們自己的開發環境比Ruby快上30倍而洋洋自得的Java程式員來說,我肯定更優的rubyJust-In-Time 編譯器即將問世了。不管如何,相比那快上1.5個數量級的情形來說,我本人還是更喜歡乾淨、簡潔、易維護的代碼。
Ruby
require 'benchmark'
def sievePerformance(n)
r = Benchmark.realtime() do
sieve = Array.new(n,true)
sieve[0..1] = [false,false]
2.upto(Integer(Math.sqrt(n)) do |i|
if sieve[i]
(2*i).step(n,i) do |j|
sieve[j] = false
end
end
end
end
r
end
Java
public class GeneratePrimes {
public static double generate(int max) {
long start = System.currentTimeMillis();
boolean sieve[] = new boolean[max];
Arrays.fill(sieve, true);
sieve[0] = false;
sieve[1] = false;
for (int i = 2; i < Math.sqrt(max); i++) {
if (sieve[i]) {
for (int j = 2*i; j < sieve.length; j+=i) {
sieve[j]= false;
}
}
}
return (System.currentTimeMillis() - start)/1000.0;
}
C++
#include <iostream>>
#include <math.h>
#include <sys/time.h>
using namespace std;
double generate(int max) {
struct timeval start;
struct timezone tz;
gettimeofday(&start, &tz);
bool *sieve = new bool[max];
for (int i=0; i<max; i++) sieve[i] = true;
sieve[0] = false;
sieve[1] = false;
for (int n=2; n<sqrt(max); n++) {
if (sieve[n]) {
for (int j=2*n; j<max; j+=n)
sieve[j] = false;
}
}
struct timeval end;
gettimeofday(&end, &tz);
double startSecond = start.tv_usec/1000000.0;
double endSecond = (end.tv_sec - start.tv_sec) + end.tv_usec/1000000.0;
return endSecond - startSecond;
}
int main(int ac, char** av) {
for (int i=100000; i<=5000000; i+=100000) {
double time = generate(i);
cout << time << endl;
}
}