Performance of lambda expressions in Java 8

    In mid-2013, with the release of Java 8, the language began to support lambda expressions, since then 4 years have passed, a lot of updates have been released, and Java 9 is coming soon (which we can probably see this year, despite constant postponements), so at the junction of time, I would like to summarize and evaluate the performance of a new tool in java and an old tool like the world, giving it a quantitative assessment.
    socmetr.lambda.comparison
    Performance evaluations have already been made several times, as other things discussed the advantages and disadvantages of lambda expressions:

    the first include:
    - simplification and reduction of code
    - the possibility of implementing a functional style
    - the possibility of parallel computing
    to the second :
    - decreased performance
    - debug's difficulty. A good

    technique and tests were described and used 5 years ago by the user dmmm ( https://habrahabr.ru/post/146718/ ), and they were taken as a basis.

    If, in short, the tests themselves were supplied with the LambdaJ project . dmmm added tests for the Guava project and adjusted them after discussion with the habr community (2012). By

    me (that is blutovi) all lambda tests were rewritten (since testing took place on alpha versions of java, and in the current state the code simply cannot be compiled), the memory status was also analyzed using Java Mission Control and a jfr file with the results was attached for each test. (Java Mission Control, a JVM diagnostic and monitoring tool, has been available since java 7 update 40, as a result of combining the ideas of two JVMs: HotSpot from Sun and JRockit from Oracle).

    How was it tested?


    The junit tests themselves consist of three phases: initialization of collections, idle execution, execution with statistics collection (time counting is carried out only at the last stage, and analysis of working with memory is carried out throughout the cycle).

    Time measurement is carried out as follows: for each of$ {z} $ iterations over time $ {Y} $, a sequential call of the test algorithm occurs. Upon its expiration, the arithmetic mean time of the algorithm execution is determined$ \ bar {Y} _ {z} $:

    $ \ bar {Y} ^ {z} = \ frac {1} {{n} _ {z}} \ sum_ {i = 0} ^ {{n} _ {z}} {Y} ^ {'} _ {i} $

    by dividing the total execution time $ {Y} ^ {'} $ by the number of times $ {n} $which he managed to fulfill. Based$ {z} $ iterations, we find the total average execution time of the algorithm:

    $ \ bar {Y} = \ frac {1} {z} \ sum_ {i = 0} ^ {z} \ bar {Y} ^ {z} _ {i} $

    By magnitude $ {z} $ (number of iterations) and $ {Y} $ (time during which the test algorithm is called) can be influenced by changing the values ​​of the constants in the class ch.lambdaj.demo.AbstractMeasurementTest:

        public static final int WARMUP_ITERATIONS_COUNT = 10;
        public static final int ITERATIONS_COUNT = 10;
        public static final int ITERATION_DURATION_MSEC = 1000;
    

    The tests were run with the activated parameters for the operation of Java Mission Control, which allowed the automatic generation of diagnostic files.

    results


    in absolute values (values than smaller , the better )
    foriterateguavajdk8 lambda
    time, nsheap Mbtime, nsheap Mbtime, nsheap Mbtime, nsheap Mb
    Extract cars original cost220.4313200.6324188.1302266.2333
    Age of youngest who bought for> 50k6367260424527163672606157278
    Find buys of youngest person60362706411.425962062606235288
    Find most bought car2356167242317158821932971190
    Find most costly sale497158.166431.6297196.182
    Group sales by buyers and sellers1214425012053254825920618447242
    Index cars by brand263.3289275.02972828226307.5278
    Print all brands473.2355455.3365540.3281514.2337
    Select all sales of a Ferrari199.366265.153210.4111200.265
    Sort sales by cost1075741075741069721566124
    Sum costs where both are males67.06372.958215.988413.7114
    in relative values (100% - this base than the value smaller , the better )
    foriterateguavajdk8 lambda
    timeheaptimeheaptimeheaptimeheap
    Extract cars original cost117%104%107%107%100%100%142%110%
    Age of youngest who bought for> 50k150%100%100%104%150%100%145%107%
    Find buys of youngest person100%104%106%100%103%100%103%111%
    Find most bought car100%100%103%102%250%116%126%114%
    Find most costly sale100%108%119%100%881%450%400%124%
    Group sales by buyers and sellers147%121%146%123%100%100%223%117%
    Index cars by brand100%128%104%131%1074%100%117%123%
    Print all brands104%126%100%130%119%100%113%120%
    Select all sales of a Ferrari100%125%133%100%106%209%100%123%
    Sort sales by cost101%103%101%103%100%100%147%172%
    Sum costs where both are males100%109%109%100%322%152%617%197%

    conclusions


    To summarize, it can be noted that the same things can be implemented using lambda expressions in different ways: however, even the most optimal options for performance will be inferior to simple solutions, and not the optimal ones can significantly affect performance.

    Thus, the iterative approach makes it possible to focus on execution speed , while Guava allows you to focus on the amount of memory used , minimizing it. Using lambda expressions seems to give only aesthetic pleasure (to my great surprise).

    Any suggestions on how to change and improve tests are welcome.

    References



    Also popular now: