2017-01-13 7 views
-3

私は以下の匿名内部クラスに対してラムダのパフォーマンスをテストするためにJMHを使用しているが、私はそれをやった方法です:私はより速く完了するためにラムダを期待していたが、私は以下の反対の結果を得るラムダ式のパフォーマンスをテストする正しい方法は?

public class LambdaVsAnonymousClass { 

@Benchmark 
@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.MICROSECONDS) 
public void testLambda() { 
    // nonCapturing expressions 
    NonCapturing nonCapturing =() -> System.out.println("ram"); 
    nonCapturing.test(); 
    // nonCapturing expressions 
    NonCapturing nonCapturing2 =() -> System.out.println("bon"); 
    nonCapturing2.test(); 
} 

@Benchmark 
@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.MICROSECONDS) 
public void testAnonymousClass() { 
    // anonymous classes 
    NonCapturing nonCapturing = new NonCapturing() { 
     @Override 
     public void test() { 
      System.out.println("ram"); 
     } 
    }; 
    nonCapturing.test(); 
    // anonymous classes 
    NonCapturing nonCapturing2 = new NonCapturing() { 
     @Override 
     public void test() { 
      System.out.println("bon"); 
     } 
    }; 
    nonCapturing2.test(); 
} 

@Benchmark 
@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.MICROSECONDS) 
public void testLambdaCapturing() { 
    // lambda expressions 
    final int i = 1; 
    Capturing capturing = n -> System.out.println(n); 
    capturing.test(i); 
    // lambda expressions 
    final int j = 2; 
    Capturing capturing2 = n -> System.out.println(n); 
    capturing2.test(j); 
} 

@Benchmark 
@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.MICROSECONDS) 
public void testAnonymousClassCapturing() { 
    // anonymous classes 
    final int i = 1; 
    Capturing capturing = new Capturing() { 
     @Override 
     public void test(int n) { 
      System.out.println(n); 
     } 
    }; 
    capturing.test(i); 
    // anonymous classes 
    final int j = 2; 
    Capturing capturing2 = new Capturing() { 
     @Override 
     public void test(int n) { 
      System.out.println(n); 
     } 
    }; 
    capturing2.test(j); 
} 

public static void main(String[] args) throws RunnerException { 
    Options opt = new OptionsBuilder() 
      .include(LambdaVsAnonymousClass.class.getSimpleName()) 
      .warmupIterations(5) 
      .measurementIterations(5) 
      .forks(1) 
      .build(); 

    new Runner(opt).run(); 
} 
} 

@FunctionalInterface 
interface NonCapturing { 
    void test(); 
} 

@FunctionalInterface 
interface Capturing { 
    void test(int n); 
} 

。間違ってテストしていますか?もしそうなら、ラムダ式のより高速なパフォーマンスを実際にテストする正しい方法は何でしょうか。

# Run complete. Total time: 00:00:42 

Benchmark           Mode Cnt Score Error Units 
LambdaVsAnonymousClass.testAnonymousClass   avgt 5 16.592 ± 4.084 us/op 
LambdaVsAnonymousClass.testAnonymousClassCapturing avgt 5 18.916 ± 4.469 us/op 
LambdaVsAnonymousClass.testLambda     avgt 5 18.618 ± 4.060 us/op 
LambdaVsAnonymousClass.testLambdaCapturing   avgt 5 22.008 ± 16.729 us/op 

注:ラムダ式を取り込むの概念が間違ってコードに示されています。 @Holgerのコメントを読んで理解してください。

+2

コンソール/ osがパフォーマンスに非常に大きな影響を与え、結果を歪める可能性があるため、ベンチマーク中にコンソール( 'System.out.println()')に印刷しないようにしたいと思います。 – Thomas

+1

[Oracleのパフォーマンス・テスト](http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf)をご覧ください。 – Flown

+0

_write_ JMHのパフォーマンスエキスパートが十分でない限り、私の助言は次のようなものです:ナノパフォーマンスに関する懸念を止め、代わりに明確なコードを書くことに集中してください。彼らは十分に速いです。 –

答えて

2

あなたはベンチマークの結果に対して批判的であり、またあなたが見るものを理解する必要があります。 ±4のエラーは、 "非キャプチャリング"テストの実行時間が16.618.6の実行時間の差よりも大きくなります。
22のような結果が表示され、エラーが±16.7の場合、アラーム音が鳴ります。

さらに、「キャプチャ」について間違った理解をしています。あなたのテストでは、ラムダ式や匿名クラスの取得はありません。パラメータがゼロの関数と、パラメータが1つの関数のみがあります。これはキャプチャとは関係ありません。唯一の違いは、あるケースでは、既存のStringを印刷し、もう1つはintStringの変換を実行していることです。しかし、これらの差異も報告された誤差よりも小さい。

エラーを考慮すると、結果は同じ大きさであり、もちろんコードの出力はラムダ式であるのか匿名の内部クラスであるのかに依存しません。ラムダ式の高速化が期待された理由は明確ではありません。ラムダ式は魔法ではありません。

+0

lambdaは静的メソッドに変換されるので、別のクラスファイルを作成してクラスなどをロードする必要はないので、Lambdaは高速であると思っていました。ラムダファクトリによる最適化もあります。私を修正してください。 –

+0

私はあなたの声明を理解していませんでした。「ラムダ式を捕らえることはありません。私はラムダ式の外にあるラムダに 'final'変数を渡していると思います。私plは私を修正することができます。 –

+0

**メソッドの引数として**値**を渡しています。その値は '42'や' 'bla.length()'や可変変数のような定数でも構いませんが、それは重要ではありません。キャプチャとは関係ありません。キャプチャは、ラムダ式自体がパラメータを使用するときではなく、外部コンテキストから変数を参照するときに発生します。 – Holger

2

正確には何を試そうとしていますか創造と呼び出し?もしそうなら、System.outを削除してください。かなり悪いので、出力はナノ秒単位で測定する必要があります。

そして、このような場合の結果は(当然ながら)とほぼ同じである:あなたがラムダをブートストラップ(任意のウォームアップなし)invokedynamicのようSingleShotTimeを測定するかどう

LambdaVsClass.testAnonymousClass   avgt 5 0.335 ± 0.069 ns/op 
LambdaVsClass.testAnonymousClassCapturing avgt 5 0.337 ± 0.051 ns/op 
LambdaVsClass.testLambda     avgt 5 0.331 ± 0.051 ns/op 
LambdaVsClass.testLambdaCapturing   avgt 5 0.337 ± 0.043 ns/op 

結果が異なるはずです。

関連する問題