3

K&R を読んで C の学習を始めたばかりの人がいて、最初のページに華氏から摂氏への変換ループが印刷されています。

#include <stdio.h>

main ()                                                                                                                                                       
{
  int fahr;                                                                                                                                                    

  for (fahr = 0; fahr<= 200000000; fahr = fahr + 20)                                                                                                                                                                                
    printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                                                                                                       
}   

彼は Java は遅いと言われました。それで、最近Javaは非常に競争力がありますが、この単純なケースではCの方がおそらく速いだろうと彼に言いました。彼を証明したくて、基本的に「System.out」を追加しました。printf() の前。

10倍以上遅くなりました。やりすぎ。私は当惑しました。String オブジェクトの作成、GC、-server、yada、yada、yada について考えました。

PrintSteam.write()実際にはほぼ 100% の時間が printf() (出力は /dev/null にパイプされます) に費やされていることがわかったとき、私はさらに困惑しました。

いくつかいじった後、私はこれを思いつきました(今のところ %f の丸めはしません):

public static void main(String... args) throws Exception {                                                                                                       
   int fahr=0;                                                                                                                                                    

    PrintWriter out = new PrintWriter(Channels.newWriter(Channels.newChannel(System.out), "US-ASCII") );                                                                                                

    int max = 2000000000;                                                                                                                                         
    for (fahr = 0; fahr<= max; fahr = fahr + 20)
      // out.printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                       
      out.println( fahr + "\t" + f(((5.0 / 9.0) * (fahr-32)) ));                                                                                                        

    out.close();                                                                                                                                            
 }                                                                                                                                                                

 private static final String f(double d) {                                                                                                                         
      return (int)d + "." + (int)((d - (int)d)*100);                                                                                                              
 }                                                                                                                                                           
} 

したがって、これは NIO を使用します。また、テストした 2 台のマシンで gcc -O2 よりも優れています。

質問:

  • C から Java へのリテラル トランススクリプト (つまりPrintStream)が非常に遅いのはなぜですか?
  • (コメントout.printf()が遅いのはなぜですか [時間の経過とともにパフォーマンスが低下する可能性があります]?)
  • 最後に: なぜ私のソリューションは C よりも高速なのですか (JVM の起動時間を含む)?
4

2 に答える 2

5

CからJava(つまり、PrintStream)への文字通りの転写が非常に遅いのはなぜですか?

System.outとさまざまなstdio(CとJava)の実装のベンチマークを行っています

(なぜコメントアウトされます。printf()が非常に遅い[時間の経過とともにパフォーマンスが低下する可能性があります]?)

浮動小数点数を文字列に(およびその逆に)変換することは、非常に複雑で時間がかかる操作です。glibcのソースコードを見てください。

そして最後に:なぜ私のソリューションはCよりも速いのですか(JVMの起動時間を含む)?

さまざまなものをベンチマークして比較しているため:

  • 整数から文字列への変換を行うJavaコード(明らかな理由で浮動小数点よりもはるかに高速です)と、Java VMがうまく機能することを願ういくつかの簡単な文字列操作に加えて、out.println()
  • ループの反復ごとに解釈された言語を実行し(はい、printfは「%d \ t%6.2f \ n」がプログラムである小さな言語のインタープリターです)、浮動小数点から文字列への変換を行うCコードに対して(これ自体は整数よりも何倍も遅い)、さらにstdio。

Cバージョンが単精度または倍精度のどちらを使用するかは明らかではありません。

于 2011-07-23T11:54:20.277 に答える
3

基本的に、あなたの実験では、ここでの計算はまったく無関係であり、ほとんどの時間は出力のフォーマットと印刷に費やされていることが示されています。したがって、言語としての C と Java のパフォーマンスをテストするのではなく、異なる文字列フォーマット ライブラリ コード (C の方が最適化されているようです) と、stdout が実際のコンソールにどのように接続されているか (ここでは Java が勝ちます) をテストします。

于 2011-07-23T11:44:07.593 に答える