2016-10-09 4 views
0

私はいくつかのJava 8 Stream APIを使って作業していました。私はちょうどStreamの内容を印刷している以下の2つのソリューションのパフォーマンスの違いを見るのは混乱しています。System.out :: printlnがJava 8の匿名クラス実装より遅いのはなぜですか?

解決方法1:

int[] array = new int[] { 0, 1, 2, 3, 4, 5 }; 
start = System.nanoTime(); 
Arrays.stream(array).forEach(System.out::println); 
System.out.println((System.nanoTime() - start)/1000000.0f); 

解決方法2:実行のために

int[] array = new int[] { 0, 1, 2, 3, 4, 5 }; 
start = System.nanoTime(); 
Arrays.stream(array).forEach(new IntConsumer() { 
    @Override 
    public void accept(int value) { 
     System.out.println(value); 
    } 
}); 
System.out.println((System.nanoTime() - start)/1000000.0f); 

Solution 1が約取っています。 Solution 2より5〜6倍多くなります。

システム構成:

  • JRE:1.8.0_101 64 bit
  • OS:Windows 10 Home 64-bit
  • RAM:4 GB
  • IDE:Eclipse Mas-1 for Java EE 64-bit

誰かが説明できる場合には参考になります、なぜですか? eはこの大きな違いですか?

JMHコード:

public class MyBenchmark { 

    @Benchmark 
    public void solution_0() { 
     int[] array = new int[] { 0, 1, 2, 3, 4, 5 }; 
     for (int i = 0; i < array.length; i++) { 
      System.out.println(array[i]);asdasdas 
     } 
    } 

    @Benchmark 
    public void solution_1() { 
     int[] array = new int[] { 0, 1, 2, 3, 4, 5 }; 
     Arrays.stream(array).forEach(new IntConsumer() { 
      @Override 
      public void accept(int value) { 
       System.out.println(value); 
      } 
     }); 
    } 

    @Benchmark 
    public void solution_2() { 
     int[] array = new int[] { 0, 1, 2, 3, 4, 5 }; 
     Arrays.stream(array).forEach(System.out::println); 
    } 
} 
+2

どのように測定していますか? 1回だけ走っていますか?マイクロベンチマークは簡単ではありません。ウォームアップ、最高値と最低値の破棄、平均値と標準偏差などを考慮する必要があります。 –

+2

Javaのマイクロベンチマークについては、どの方法が高速であるかを知る前に覚えておく必要があります。 Jmhを検索する –

+0

@FedericoPeraltaSchaffner私は100回の反復でそれを取り上げ、大きな変更を加えていた最初のいくつかの要素をスキップしました。私は同じプログラムを4〜5回実行し、毎回の結果は同じでした。 –

答えて

9

あなたは、メソッド参照のインスタンス化ではなく、その実行時のパフォーマンスを測定しています。

メソッドリファレンス(System.out::println)の最初の使用では、JVMはIntConsumerインターフェイスを実装する内部クラスを作成する必要があります。もちろん、これには時間がかかります。これはアプリケーションの有効期間中に1回だけ実行されます。

2番目のケースでは、このような匿名クラスを自分で作成しました。

メソッド参照のランタイムパフォーマンスを測定する場合は、ベンチマークメタデータを修正する必要があります。 「How do I write a correct micro-benchmark in Java?

+0

こんにちは..私はMode.AllでJMHを試しましたが、結果は 'ns/op'と' ops/ns'でのみ得られます。理想的には、どちらも両方のアルゴリズムで同じである必要があります。私は絶対的な平均時間を得るために何かを見つけることができませんでした。どのようなアイデアが平均時間を確認するのに役立つだろう。 –

+0

@AmberBeriwalあなたが探している平均時間は 'ns/op'ではありませんか? – apangin

+0

ナノ秒/動作と理解していますが、間違っていれば私を修正してください。したがって、私の理解によれば、コード1に100個の操作が含まれ、1000 nsで完了すると、10 ns/opになります。さて、もしコード2が200個の操作を含み、2000ミリ秒で完了すれば、それは10 ns/opとなるでしょう。しかし、実際のコード2では2000ミリ秒かかる。 –

関連する問題