JavaはCより速かった
仕事をせずに遊んでいる人のコードを、家のJava(Java6)で試してみました。
シェルで動かして、グラフはgnuplotです。ハイテク満載です。
$ seq 1 100 |xargs -n 1 java test |tee /tmp/java-cl.out $ seq 1 100 |xargs -n 1 java -server test |tee /tmp/java-sv.out
横軸は同時スレッド数、縦軸が時間(ミリ秒)です。要は低い方が速くて優秀です。
クライアントVMとサーバVMの差がすごいです。と言うか、サーバVMが優秀すぎます。と言うか、サーバVMの数値は変です。トータルでまわるループ数が線形に増えているはずなのに、処理時間があまり増えていません。
試しにと思って、Cのコードと比較してみました(コードは最後を参照)。スレッド数のベースを増やして200から300にしました。ありえない結果がでました。JavaのサーバVMがCより速い結果になりました。
@ITの記事を読んで感心する人なら、Javaは素晴らしい!、と考えるかもしれませんが、そんなことは一瞬たりとも考えることは無くて、なんかおかしい、と考えます。
元のJavaのコードは
for (int j = 0; j < 100; j++) { for (int i = 0; i < 1000; i++) { synchronized(this) { total += i; } } }
こういうコードなのですが、もしかしてと思い、試しにロックをループの外に追い出してみました。
synchronized(this) { for (int j = 0; j < 100; j++) { for (int i = 0; i < 1000; i++) { total += i; } } }
ロックを追い出した版と追い出していない版のグラフが以下です(java-sv3.outが追い出した版ですが、まあ、どちらでもいいですね。誤差の範囲です)。
さすがJava、やってくれます。サーバVMはこんなことするんですね。
しかし、ここで話が終わりません。ロックをループの外に追い出したC版と比較しても、まだJava版が速いのです。恐ろしいことです。
ロックをループの外に追い出すと、上の2重ループはかなり違うコードで同じ結果にできます。もしかしてループ消しているのでしょうか。ここまでやっているとしたら、それはそれでJavaのサーバVMは凄いことです。
ちなみに、元のJavaコードをそのまま使うとスレッド生成の差がC版と違うので、Java版でもスレッド生成から含めて計測しています。
// 対照に使ったCのコード #include <stdio.h> #include <pthread.h> #include <sys/time.h> #include <time.h> static int total; static pthread_mutex_t mutex; static void* doit(void* data) { int i,j; for (j = 0; j < 100; j++) { for (i = 0; i < 1000; i++) { pthread_mutex_lock(&mutex); total++; pthread_mutex_unlock(&mutex); } } } int main(int argc, char** argv) { int num_thr = atoi(argv[1]); pthread_t thr[1024]; struct timeval tv1; struct timeval tv2; int i; pthread_mutex_init(&mutex, NULL); gettimeofday(&tv1, NULL); for (i = 0; i < num_thr; i++) { pthread_create(&thr[i], NULL, doit, NULL); } for (i = 0; i < num_thr; i++) { pthread_join(thr[i], NULL); } gettimeofday(&tv2, NULL); printf("%d %d %d\n", num_thr, (tv2.tv_sec - tv1.tv_sec) * (long)1000 + (((tv2.tv_usec - tv1.tv_usec) / 1000) % 1000), total); return 0; }
- Category(s)
- カテゴリなし
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/inoue/java-vs-c/tbping
Re:JavaはCより速かった
Re:JavaはCより速かった
Javaの理論と実践: 動的コンパイルとパフォーマンス測定
http://www.ibm.com/developerworks/jp/java/library/j-jtp12214/
Javaの理論と実践: 欠陥マイクロベンチマークを分析する
http://www.ibm.com/developerworks/jp/java/library/j-jtp02225/
サーバVMで、スレッド数に対して処理時間が延びなかったのは、この記事の「デッドコード削除」に近いような気がします(インクリメントするだけでtotalにアクセスしていないから?)
以下引用:
doSomeStuff()メソッドはスレッドに対して何かすべきことを与えるはずなので、StupidThreadBenchmarkを実行すると、複数スレッドのスケジューリングのオーバーヘッドが何かしらあるだろうと推測できます。ところがコンパイラーはuselessSumが全く使われないので、doSomeStuffのコードは全てデッドコードであると判断し、全てを除去して最適化してしまいます。ループの中身が無くなってしまうと、そのループも無くなり、doSomeStuffは完全に空になって残ります。