【问题标题】:Faster way for transforming entity in dto在 dto 中转换实体的更快方法
【发布时间】:2017-07-10 23:09:48
【问题描述】:

哪个更快?添加到foreach 中的列表或stream 中的映射和收集。

//Solution 1
List<Card> cards = mobileUserService.getCurrentUser().getUserCard();

final List<CardDTO> dtos = new ArrayList<>(cards.size());

cards.forEach(card -> dtos.add(cardTransformer.transform(card)));

//Solution 2
List<Card> cards = mobileUserService.getCurrentUser().getUserCard();

List<CardDTO> dtos = cards.stream()
        .map(cardTransformer::transform)
        .collect(Collectors.toList());

基准测试:

在大多数情况下,foreach 似乎更快。

测试代码变体1:

   List<Card> cards = new ArrayList<>();
       for (int i = 0; i < count; i++) {
        Card c = Card.createFakeCard();
        cards.add(c);
    }


    long startTime1 = System.nanoTime();
    //Solution 1
    final List<CardDTO> dtos = new ArrayList<>(cards.size());
    cards.forEach(card -> dtos.add(cardTransformer.transform(card)));
    long endTime1 = System.nanoTime();


    long startTime2 = System.nanoTime();
    //Solution 2
    List<CardDTO> dtos2 = cards.stream()
            .map(cardTransformer::transform)
            .collect(Collectors.toList());

    long endTime2 = System.nanoTime();


    double runtime1 = (endTime1 - startTime1) / Math.pow(10, 6);
    double runtime2 = (endTime2 - startTime2) / Math.pow(10, 6);
    log.error("Number of elements: " + count + "\n" +
            "Solution 1 " +
            "Total time (ms): " + runtime1 + "\n" +
            "Solution 2 " +
            "Total time (ms): " + runtime2);

结果变体 1:

Number of elements: 1
Solution 1 Total time (ms): 3.862259
Solution 2 Total time (ms): 8.919641
Number of elements: 1
Solution 1 Total time (ms): 0.012556
Solution 2 Total time (ms): 0.032712
Number of elements: 1
Solution 1 Total time (ms): 0.011565
Solution 2 Total time (ms): 0.034363
Number of elements: 2
Solution 1 Total time (ms): 0.01619
Solution 2 Total time (ms): 0.03965
Number of elements: 10
Solution 1 Total time (ms): 0.020486
Solution 2 Total time (ms): 0.044607
Number of elements: 100
Solution 1 Total time (ms): 0.395842
Solution 2 Total time (ms): 0.729233
Number of elements: 1000
Solution 1 Total time (ms): 0.276229
Solution 2 Total time (ms): 0.37866
Number of elements: 5000
Solution 1 Total time (ms): 0.987951
Solution 2 Total time (ms): 1.092693
Number of elements: 10000
Solution 1 Total time (ms): 2.701169
Solution 2 Total time (ms): 3.287001
Number of elements: 20000
Solution 1 Total time (ms): 11.095115
Solution 2 Total time (ms): 11.3046
Number of elements: 50000
Solution 1 Total time (ms): 4.339383
Solution 2 Total time (ms): 6.235984
Number of elements: 100000
Solution 1 Total time (ms): 8.312332
Solution 2 Total time (ms): 9.088485

测试代码变体 2:

   List<Card> cards = new ArrayList<>();
       for (int i = 0; i < count; i++) {
        Card c = Card.createFakeCard();
        cards.add(c);
    }



    long startTime2 = System.nanoTime();
    //Solution 2
    List<CardDTO> dtos2 = cards.stream()
            .map(cardTransformer::transform)
            .collect(Collectors.toList());

    long endTime2 = System.nanoTime();


    long startTime1 = System.nanoTime();
    //Solution 1
    final List<CardDTO> dtos = new ArrayList<>(cards.size());
    cards.forEach(card -> dtos.add(cardTransformer.transform(card)));
    long endTime1 = System.nanoTime();

    double runtime1 = (endTime1 - startTime1) / Math.pow(10, 6);
    double runtime2 = (endTime2 - startTime2) / Math.pow(10, 6);
    log.error("Number of elements: " + count + "\n" +
            "Solution 1 " +
            "Total time (ms): " + runtime1 + "\n" +
            "Solution 2 " +
            "Total time (ms): " + runtime2);

结果变体 2:

Number of elements: 1
Solution 1 Total time (ms): 1.672247
Solution 2 Total time (ms): 9.868603
Number of elements: 1
Solution 1 Total time (ms): 0.005617
Solution 2 Total time (ms): 0.043946
Number of elements: 1
Solution 1 Total time (ms): 0.005618
Solution 2 Total time (ms): 0.040971
Number of elements: 2
Solution 1 Total time (ms): 0.006278
Solution 2 Total time (ms): 0.041963
Number of elements: 10
Solution 1 Total time (ms): 0.011564
Solution 2 Total time (ms): 0.045929
Number of elements: 100
Solution 1 Total time (ms): 0.065093
Solution 2 Total time (ms): 0.121263
Number of elements: 1000
Solution 1 Total time (ms): 0.65555
Solution 2 Total time (ms): 0.968456
Number of elements: 5000
Solution 1 Total time (ms): 0.779127
Solution 2 Total time (ms): 1.244686
Number of elements: 10000
Solution 1 Total time (ms): 2.03769
Solution 2 Total time (ms): 2.337048
Number of elements: 20000
Solution 1 Total time (ms): 6.12232
Solution 2 Total time (ms): 6.038063
Number of elements: 50000
Solution 1 Total time (ms): 6.12232
Solution 2 Total time (ms): 8.463334
Number of elements: 100000
Solution 1 Total time (ms): 16.468047
Solution 2 Total time (ms): 17.86109

【问题讨论】:

  • 您的基准测试结果如何?
  • 为了更具声明性,您可以将 map(card -&gt; cardTransformer.transform(card)) 替换为 map(cardTransformer::transform)
  • 您认为有显着差异吗?如果是,为什么?
  • 基准测试的问题在于它们总是给出答案,但答案并不一定意味着什么。像这样的基准(运行几次并使用nanoTime() 测量)通常毫无价值。但最重要的是,不要再担心微性能问题(这些问题确实存在),而是将所有这些大脑周期应用到编写清晰、可维护的代码上。您将获得更好的投资回报。

标签: java foreach java-8 java-stream


【解决方案1】:

我不是 JVM 如何处理 lambda 的专家,但几个月前我自己做了一些研究,所以... 我认为关键是您的流中“lambdas”的数量。

每次编写 lambda 时,都会发生 2 件主要事情:

  1. 在编译时,lambda 将被提取为宿主类的私有方法。你实际上可以看到使用javap
  2. 在运行时,JVM 将创建一个对象来调用该私有方法。 (这里有很多有趣的东西,但为了简单起见)

然后在您的代码中,第一种情况只有 1 个 lambda,但第二种情况有 2 个。因此,在某些时候,JVM 将不得不为您的第二种情况连接、创建和实例化一个对象,两次。这就是您的第一个代码“更快”的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 2019-04-22
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 2019-05-01
    相关资源
    最近更新 更多