2013-06-11 10 views
17

長い間、私はC++をjavascriptより速く考えていました。しかし、今日、私は2つの言語で浮動小数点計算の速度を比較するベンチマークスクリプトを作成し、結果は素晴らしいです!JavascriptはC++よりも4倍高速ですか?

Javascriptは、C++よりもほぼ4倍高速です!

i5-430Mラップトップで同じ言語を使用して、a = a + bを100000000回実行しました。 C++は約410ミリ秒かかりますが、javascriptは約120ミリ秒しかかかりません。

JavaScriptがこのように高速で実行できる理由は本当にわかりません。誰もそれを説明できますか?

私はjavascriptのために使用されるコードは(nodejsで実行)である:(G ++でコンパイル)

(function() { 
    var a = 3.1415926, b = 2.718; 
    var i, j, d1, d2; 
    for(j=0; j<10; j++) { 
     d1 = new Date(); 
     for(i=0; i<100000000; i++) { 
      a = a + b; 
     } 
     d2 = new Date(); 
     console.log("Time Cost:" + (d2.getTime() - d1.getTime()) + "ms"); 
    } 
    console.log("a = " + a); 
})(); 

とCのコードは++です:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double a = 3.1415926, b = 2.718; 
    int i, j; 
    clock_t start, end; 
    for(j=0; j<10; j++) { 
     start = clock(); 
     for(i=0; i<100000000; i++) { 
      a = a + b; 
     } 
     end = clock(); 
     printf("Time Cost: %dms\n", (end - start) * 1000/CLOCKS_PER_SEC); 
    } 
    printf("a = %lf\n", a); 
    return 0; 
} 
+0

いいえ、私はg ++ xxx.cppコマンドを使用します。それを最適化するために使用するパラメータは何ですか?私はcppには慣れていません。 – streaver91

+7

'-O3 -ffast-math'を追加して、C++タイミングがどうなるかを見てください。 –

+8

* "長い間、私はいつもC++がJavaScriptより速くなければならないと思っています" * Javascriptエンジンは通常C++で実装されていることを理解しています – jamylak

答えて

143

私はいくつかの悪いニュースを有することができますLinuxシステム(少なくともこの状況ではPOSIXに準拠しています)を使用している場合は、あなたのために。 clock()コールは、プログラムによって消費され、CLOCKS_PER_SECでスケーリングされたクロックティック数を返します。これは1,000,000です。あなたは上のようなシステムなら、あなたは(JS online docsあたりとして)CとJavaScriptについてミリためマイクロに話している、意味

。したがって、JSが4倍高速になるのではなく、C++は実際に250倍高速です。

#include <stdio.h> 
#include <time.h> 
#include <stdlib.h> 

#define MILLION * 1000000 

static void commaOut (int n, char c) { 
    if (n < 1000) { 
     printf ("%d%c", n, c); 
     return; 
    } 

    commaOut (n/1000, ','); 
    printf ("%03d%c", n % 1000, c); 
} 

int main (int argc, char *argv[]) { 
    int i; 

    system("date"); 
    clock_t start = clock(); 
    clock_t end = start; 

    while (end - start < 30 MILLION) { 
     for (i = 10 MILLION; i > 0; i--) {}; 
     end = clock(); 
    } 

    system("date"); 
    commaOut (end - start, '\n'); 

    return 0; 
} 

:それはあなたがCLOCKS_PER_SECONDが万人以外の何かであるシステムにしているのかもしれ

さて、あなたはそれが同じ値でスケーリングしていますかどうかを確認するために、あなたのシステム上で次のプログラムを実行することができます私のボックスの出力は:

Tuesday 17 November 11:53:01 AWST 2015 
Tuesday 17 November 11:53:31 AWST 2015 
30,001,946 

は、倍率が100万であることを示しています。そのプログラムを実行したり、CLOCKS_PER_SECを調べてではなく、の倍率が100万でない場合は、他のものを調べる必要があります。


最初の手順は、コードが実際にコンパイラによって最適化されていることを確認することです。つまり、たとえばgccには-O2または-O3を設定します。最適化されていないコードで自分のシステムで

、私は以下を参照してください。

Time Cost: 320ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
a = 2717999973.760710 

をし、それは、3倍高速-O2とだわずかに異なる答えとはいえ、しかし唯一パーセントのおよそ百万分の一によって:

Time Cost: 140ms 
Time Cost: 110ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
a = 2718000003.159864 

これは、2つの状況を互いに引き合わせることになると思います.JavaScriptは見た目の都度、各トークンが解釈される昔のような獣のように解釈されないからです。

現代のJavaScriptエンジン(V8、サイなど)C.

ようなコンパイル言語の性能がほぼ等しく可能にし得る中間形式に(または機械語に)コードをコンパイルすることができるが、正直であることJavaScriptやC++の速度を選択する傾向はなく、自分の強みに合わせて選択します。ブラウザの中にはCコンパイラがたくさん浮かんでいないので、JavaScriptで書かれた多くのオペレーティングシステムや組み込みアプリケーションに気付かなかった。

+17

男。あなたは私たちを救った! –

+1

私はそうではないと思う、400msは何かが感じやすいです。出力はjavascriptよりも遅いです。 – streaver91

+0

@ user2189264の場合、プロセスの起動と切断には多分時間がかかります。私は "証明"を表示するために更新します。 – paxdiablo

6

最適化をオンにして簡単なテストを行ったところ、古代AMD 64 X2プロセッサでは約150ミリ秒、合理的に最近のインテルi7プロセッサでは約90ミリ秒の結果が得られました。

次に、C++を使いたい理由があることを少し考えました。私はこれを取得するには、ループの4回の繰り返しをアンロール:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double a = 3.1415926, b = 2.718; 
    double c = 0.0, d=0.0, e=0.0; 
    int i, j; 
    clock_t start, end; 
    for(j=0; j<10; j++) { 
     start = clock(); 
     for(i=0; i<100000000; i+=4) { 
      a += b; 
      c += b; 
      d += b; 
      e += b; 
     } 
     a += c + d + e; 
     end = clock(); 
     printf("Time Cost: %fms\n", (1000.0 * (end - start))/CLOCKS_PER_SEC); 
    } 
    printf("a = %lf\n", a); 
    return 0; 
} 

このAMDにおよそ44msで実行するC++コードは(インテルのこのバージョンを実行するのを忘れて)みましょう。その後、私はコンパイラの自動ベクトル化(VC++の-Qpar)を有効にしました。これにより、AMDでは約40ミリ秒、インテルでは約30ミリ秒まで、少しでも時間が短縮されました。

要点:C++を使いたい場合は、実際にコンパイラの使い方を学ぶ必要があります。本当に良い結果を得たい場合は、より良いコードを書く方法を学びたいと思うかもしれません。

私は次を追加する必要があります:ループをアンロールしてJavascriptでバージョンをテストしようとしませんでした。そうすることで、JSにも同様の(あるいは少なくともいくらか)速度改善がもたらされるかもしれません。個人的には、コードを高速化するのは、JavascriptをC++と比較するよりも面白いと思います。

このようなコードを高速で実行したい場合は、ループをアンロールします(少なくともC++では)。

並列計算の主題が発生して以来、OpenMPを使用して別のバージョンを追加すると思いました。私がそれをしている間、私はコードを少しきれいにしたので、何が起こっているのかを把握することができました。また、内部ループの実行ごとに時間の代わりに全体の時間を表示するために、タイミングコードを少し変更しました。結果のコードは、このように見えた:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double total = 0.0; 
    double inc = 2.718; 
    int i, j; 
    clock_t start, end; 
    start = clock(); 

    #pragma omp parallel for reduction(+:total) firstprivate(inc) 
    for(j=0; j<10; j++) { 
     double a=0.0, b=0.0, c=0.0, d=0.0; 
     for(i=0; i<100000000; i+=4) { 
      a += inc; 
      b += inc; 
      c += inc; 
      d += inc; 
     } 
     total += a + b + c + d; 
    } 
    end = clock(); 
    printf("Time Cost: %fms\n", (1000.0 * (end - start))/CLOCKS_PER_SEC); 

    printf("a = %lf\n", total); 
    return 0; 
} 

プライマリここでさらに、以下の(明らかに多少難解)ラインである:これは、複数のスレッドで外部ループを実行するようにコンパイラに指示

#pragma omp parallel for reduction(+:total) firstprivate(inc) 

を用いて、スレッドごとにincの別個のコピーを作成し、パラレルセクションの後に個々の値totalを一緒に追加します。

結果は、おそらくあなたが期待するものです。コンパイラの-openmpフラグでOpenMPを有効にしないと、報告された時間は以前に実行したときの約10倍です(AMDの場合は409 ms、Intelの場合は323 MS)。 OpenMPをオンにすると、AMDの場合は217ミリ秒、インテルの場合は100ミリ秒になります。

インテルでは、元のバージョンは外側のループの1回の反復で90msかかりました。このバージョンでは、外側ループの10回の反復すべてでわずかに長くなり(100ms)、速度は約9:1向上します。より多くのコアを持つマシンでは、さらに多くの改善が期待できます(必要に応じて、手動でスレッド数を調整することはできますが、OpenMPは通常、すべてのコアを自動的に利用します)。

http://benchmarksgame.alioth.debian.org/

ベンチマークに言語のすべての種類:1が見てもよう

+0

クール!明示的な並列コードのない並列コンピューティング – streaver91

+2

@ user2189264:はい、いいえ - それはまだ1つのコアで実行されています。もう少し多くの作業(たとえば、いくつかのopenMPディレクティブ)を行うことで、複数のコアでも実行できるようになり、スピードを効果的に倍増させることができます。私がこれまで行ってきたのは、単一のコア(スレッドレベルの並列処理ではなく、命令レベルの並列処理が公開されている)上のリソースをより有効に活用できるようにしています。 –

0

これは、偏光トピックです。

Javascript V8などは、例のように単純なループではうまくやっていますが、おそらく非常によく似たマシンコードを生成しています。 ほとんどの「ユーザーの近く」アプリケーションでは、Javscriptは確かに優れた選択ですが、メモリの無駄や、複雑なアルゴリズム/アプリケーションのために何度も避けることのできないパフォーマンスの低下(制御不足)があります。

関連する問題