2017-02-14 2 views
0

JavaとC#でチェックとアンチェックの整数オーバーフローの時間差を測定しようとしています。C#とJavaのオーバーフローチェックが狂ったパフォーマンス偏差

私は、チェックされたJavaコードがC#に比べて高速かつ高速になることに気付きました。何故ですか?

C#コードとJavaチェックコードの間に大きな違いがあるのはなぜですか?C#コードとJavaチェックなしコードの両方がほぼ同じように機能するのはなぜですか?

C#コード:

class Program 
{ 

    static void Checked() 
    { 
     Random random = new Random(); 
     Stopwatch time = new Stopwatch(); 
     time.Start(); 
     int rez = 0; 
     for (int i = 0; i < 500000; i++) 
     { 
      int a = random.Next(Int32.MaxValue); // edit 
      int b = random.Next(Int32.MaxValue); // edit 
      try 
      { 
       checked 
       { 
        rez = a + b; 
        // rez = random.Next(Int32.MaxValue) + random.Next(Int32.MaxValue); // edit 
       } 
      } 
      catch { } 
     } 
     time.Stop(); 
     Console.WriteLine(rez); 
     Console.WriteLine("Checked: " + time.ElapsedMilliseconds + "ms"); 

    } 
    static void Unchecked() 
    { 
     Random random = new Random(); 
     Stopwatch time = new Stopwatch(); 
     time.Start(); 
     for (int i = 0; i < 500000; i++) 
     { 
      int rez = random.Next(Int32.MaxValue) + random.Next(Int32.MaxValue); 
     } 
     time.Stop(); 
     Console.WriteLine("Unchecked: " + time.ElapsedMilliseconds + "ms"); 
    } 
    static void Main(string[] args) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      Checked(); 
      Unchecked(); 

      Console.WriteLine(); 
     } 
    } 
} 

Javaコード:

public class CheckedUnchecked { 
    public static void checked() { 
     Random random = new Random(); 
     long start = System.nanoTime(); 
     int rez = 0; 
     for (int i = 0; i < 500000; i++) { 
      try { 
       rez = Math.addExact(random.nextInt(Integer.MAX_VALUE), random.nextInt(Integer.MAX_VALUE)); 
      }catch(Exception e) {} 
     } 
     System.out.println(rez); // prevent jvm from optimizing variable out, ignore in final output 
     long time = System.nanoTime() - start; 
     System.out.printf("checked %.1f ms%n", time/1e6); 
    } 

    public static void unchecked() { 

     Random random = new Random(); 
     long start = System.nanoTime(); 
     int rez = 0; 
     for (int i = 0; i < 500000; i++) { 
      rez = random.nextInt(Integer.MAX_VALUE) + random.nextInt(Integer.MAX_VALUE); 
     } 
     System.out.println(rez); 
     long time = System.nanoTime() - start; 
     System.out.printf("unchecked %.1f ms%n", time/1e6); 
    } 

    public static void main(String[] args) { 
     for (int i = 0; i < 10; i++) { 
      checked(); 
      unchecked(); 
      System.out.println(); 
     } 
    } 
} 

C番号:チェック

:7846ms 未チェック:チェック17ms

:7806ms 未確認:17ms

チェック:7788ms未確認 :チェック17ms

:7798ms未確認 :チェック17ms

:7739ms未確認 :チェック17ms

:7907ms未確認 :17ms

チェック:7840ms 未チェック:17ms

チェック:7805msチェックなし :チェック17ms

:7836msチェックなし :チェック17ms

:7771ms チェックなし:17ms

Javaは:

は693.7ミリ 未確認23.6ミリ

をチェックします

チェック済み799.9 ms 未チェック14.9 ms

は 未確認13.8ミリ

は482.8ミリ 未確認14.1ミリ

が 未確認13.7ミリ

が 未確認13.7ミリ

は490.1ミリを確認487.0ミリを確認483.4ミリを確認確認488.1ミリを確認しました 未チェック14.1 ms

チェック済み499.9 ms 未チェック13.8 ms

チェック済み485.9 ms 未チェック13。 CPU:インテルCore i3-2100 3.10GHz のWindows 10 64ビット

Javaバージョン "1.8.0_121"

@ 9ミリ

は481.2ミリ 未確認13.8ミリ

システム情報をチェックします

Java(TM)SE Runtime Environment(ビルド1.8.0_121-b13)

Java HotSpot(TM)64ビットサーバーVM(ビルド25.121-b13、混合モード

VS2015 Community Editionリリース構成に付属のC#デフォルトコンパイラ

+0

チェックされたブロックの前に2つの乱数を作成し、チェックされたブロックに追加するだけです。 –

+0

@ k5_しました。さらに遅くても8000ms前後になります。私は引数が常に範囲内にあることを知っているので、random.Nextも例外をスローすることができたので、tryブロックからもそれを移動させることができます。 – stigma6

+0

ベンチマーク時に出力ラインを含めないでください。特にプラットフォームの1つではありません。 –

答えて

0

パフォーマンスが悪いのは、パフォーマンスに悪影響を与える例外処理によるものです。あなたが1と2

結論の間に大きな違いが表示されます

1) int n; if (int.TryParse("ABC",out n) n=-999 ; 

2) int n; try {n=int.Parse("ABC"); } catch { n=-999 ; } 

:あなたのループの場合は例えば

、コードの一部は、時間の何千も呼ばれ、にしてみてください例外を発生させる条件の事前テストによって例外を発生させないようにしてください。

+0

チェックされたブロックと例外処理は関係ありません。興味深いことに、Javaがそれほど多くのパフォーマンス・ヒットを取らないことを見ても、Math.addExactをキャッチしようとしています。 – stigma6

+1

@ stigma6: "rez = a + b;"を置き換えた場合"long l = a + b; if(l <= int.MaxValue)rez =(int)l;"とすると、実際のパフォーマンスが向上します(キャッチは発生しません)。私は "catch(Exception e)"がなくても、e(メッセージ、スタックトレース、内部例外など)を初期化するために行われた作業の大半は体系的にC#で行われていると思います。確認するには、ILコードを調べる必要があります。 – Graffito