恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

一、粉丝的反馈

恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

问:stream比for循环慢5倍,用这个是为了啥?
答:互联网是一个新闻泛滥的时代,三人成虎,以假乱真的事情时刻发生。作为一个手艺开发者,要自己去着手去做,不要人云亦云。

简直,这位粉丝说的这篇文章我也看过,我就不贴地址了,也没需要给他带流量。怎么说呢?就是一个不明白测试的、不入流开发工程师做的性能测试,给出了一个危言耸听的结论。

二、所有性能测试结论都是片面的

性能测试是需要的,但针对性能测试的效果,永远要持怀疑态度。为什么这么说?

  • 性能测试脱离营业场景就是片面的性能测试。你能笼罩所有的营业场景么?
  • 性能测试脱离硬件环境就是片面的性能测试。你能笼罩所有的硬件环境么?
  • 性能测试脱离开发人员的知识面就是片面的性能测试。你能笼罩种种开发人员奇奇怪怪的代码么?

以是,我从来不相信网上的任何性能测试的文章。通常我自己的从事的营业场景,我都要在靠近生产环境的机械上自己测试一遍。 所有性能测试结论都是片面的,只有你生产环境下的运行效果才是真的。

三、着手测试Stream的性能

3.1.环境

windows10 、16G内存、i7-7700HQ 2.8HZ 、64位操作系统、JDK 1.8.0_171

3.2.测试用例与测试结论

我们在上一节,已经讲过:

  • 针对差别的数据结构,Stream流的执行效率是不一样的
  • 针对差别的数据源,Stream流的执行效率也是不一样的

以是记着笔者的话:所有性能测试结论都是片面的,你要自己着手做,相信你自己的代码和你的环境下的测试!我的测试效果仅仅代表我自己的测试用例和测试数据结构!

3.2.1.测试用例一

测试用例:5亿个int随机数,求最小值
测试结论(测试代码见后文):

VulnHub CengBox2靶机渗透

  • 使用通俗for循环,执行效率是Stream串行流的2倍。也就是说通俗for循环性能更好。
  • Stream并行流盘算是通俗for循环执行效率的4-5倍。
  • Stream并行流盘算 > 通俗for循环 > Stream串行流盘算

恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

3.2.测试用例二

测试用例:长度为10的1000000随机字符串,求最小值
测试结论(测试代码见后文):

  • 通俗for循环执行效率与Stream串行流平起平坐
  • Stream并行流的执行效率远高于通俗for循环
  • Stream并行流盘算 > 通俗for循环 = Stream串行流盘算

恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

3.3.测试用例三

测试用例:10个用户,每人200个订单。按用户统计订单的总价。
测试结论(测试代码见后文):

  • Stream并行流的执行效率远高于通俗for循环
  • Stream串行流的执行效率大于即是通俗for循环
  • Stream并行流盘算 > Stream串行流盘算 >= 通俗for循环
    恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云

四、最终测试结论

  • 对于简朴的数字(list-Int)遍历,通俗for循环效率简直比Stream串行流执行效率高(1.5-2.5倍)。然则Stream流可以行使并行执行的方式施展CPU的多核优势,因此并行流盘算执行效率高于for循环。
  • 对于list-Object类型的数据遍历,通俗for循环和Stream串行流比也没有任何优势可言,更不用提Stream并行流盘算。

虽然在差别的场景、差别的数据结构、差别的硬件环境下。Stream流与for循环性能测试效果差异较大,甚至发生逆转。然则总体上而言

  • Stream并行流盘算 >> 通俗for循环 ~= Stream串行流盘算 (之以是用两个大于号,你细品)
  • 数据容量越大,Stream流的执行效率越高。
  • Stream并行流盘算通常能够比较好的行使CPU的多核优势。CPU焦点越多,Stream并行流盘算效率越高。

stream比for循环慢5倍?也许吧,单核CPU、串行Stream的int类型数据遍历?我没试过这种场景,然则我知道这不是应用系统的焦点场景。看了十几篇测试博文,和我的测试效果。我的结论是: 在大多数的焦点营业场景下及常用数据结构下,Stream的执行效率比for循环更高。 究竟我们的营业中通常是实实在在的实体工具,没事谁总对List<Int>类型举行遍历?谁的生产服务器是单核?。

五、测试代码

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>junitperf</artifactId>
    <version>2.0.0</version>
</dependency>

测试用例一:

import com.github.houbb.junitperf.core.annotation.JunitPerfConfig;
import com.github.houbb.junitperf.core.report.impl.HtmlReporter;
import org.junit.jupiter.api.BeforeAll;

import java.util.Arrays;
import java.util.Random;

public class StreamIntTest {

    public static int[] arr;

    @BeforeAll
    public static void init() {
        arr = new int[500000000];  //5亿个随机Int
        randomInt(arr);
    }

    @JunitPerfConfig( warmUp = 1000, reporter = {HtmlReporter.class})
    public void testIntFor() {
        minIntFor(arr);
    }

    @JunitPerfConfig( warmUp = 1000, reporter = {HtmlReporter.class})
    public void testIntParallelStream() {
        minIntParallelStream(arr);
    }

    @JunitPerfConfig( warmUp = 1000, reporter = {HtmlReporter.class})
    public void testIntStream() {
        minIntStream(arr);
    }

    private int minIntStream(int[] arr) {
        return Arrays.stream(arr).min().getAsInt();
    }

    private int minIntParallelStream(int[] arr) {
        return Arrays.stream(arr).parallel().min().getAsInt();
    }

    private int minIntFor(int[] arr) {
        int min = Integer.MAX_VALUE;
        for (int anArr : arr) {
            if (anArr < min) {
                min = anArr;
            }
        }
        return min;
    }

    private static void randomInt(int[] arr) {
        Random r = new Random();
        for (int i = 0; i < arr.length; i++) {
            arr[i] = r.nextInt();
        }
    }
}

测试用例二:

import com.github.houbb.junitperf.core.annotation.JunitPerfConfig;
import com.github.houbb.junitperf.core.report.impl.HtmlReporter;
import org.junit.jupiter.api.BeforeAll;

import java.util.ArrayList;
import java.util.Random;

public class StreamStringTest {

    public static ArrayList<String> list;

    @BeforeAll
    public static void init() {
        list = randomStringList(1000000);
    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void testMinStringForLoop(){
        String minStr = null;
        boolean first = true;
        for(String str : list){
            if(first){
                first = false;
                minStr = str;
            }
            if(minStr.compareTo(str)>0){
                minStr = str;
            }
        }
    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void textMinStringStream(){
        list.stream().min(String::compareTo).get();
    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void testMinStringParallelStream(){
        list.stream().parallel().min(String::compareTo).get();
    }

    private static ArrayList<String> randomStringList(int listLength){
        ArrayList<String> list = new ArrayList<>(listLength);
        Random rand = new Random();
        int strLength = 10;
        StringBuilder buf = new StringBuilder(strLength);
        for(int i=0; i<listLength; i++){
            buf.delete(0, buf.length());
            for(int j=0; j<strLength; j++){
                buf.append((char)('a'+ rand.nextInt(26)));
            }
            list.add(buf.toString());
        }
        return list;
    }
}

测试用例三:

import com.github.houbb.junitperf.core.annotation.JunitPerfConfig;
import com.github.houbb.junitperf.core.report.impl.HtmlReporter;
import org.junit.jupiter.api.BeforeAll;

import java.util.*;
import java.util.stream.Collectors;

public class StreamObjectTest {

    public static List<Order> orders;

    @BeforeAll
    public static void init() {
        orders = Order.genOrders(10);
    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void testSumOrderForLoop(){
        Map<String, Double> map = new HashMap<>();
        for(Order od : orders){
            String userName = od.getUserName();
            Double v; 
            if((v=map.get(userName)) != null){
                map.put(userName, v+od.getPrice());
            }else{
                map.put(userName, od.getPrice());
            }
        }

    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void testSumOrderStream(){
        orders.stream().collect(
                Collectors.groupingBy(Order::getUserName, 
                        Collectors.summingDouble(Order::getPrice)));
    }

    @JunitPerfConfig(duration = 10000, warmUp = 1000, reporter = {HtmlReporter.class})
    public void testSumOrderParallelStream(){
        orders.parallelStream().collect(
                Collectors.groupingBy(Order::getUserName, 
                        Collectors.summingDouble(Order::getPrice)));
    }
}


class Order{
    private String userName;
    private double price;
    private long timestamp;
    public Order(String userName, double price, long timestamp) {
        this.userName = userName;
        this.price = price;
        this.timestamp = timestamp;
    }
    public String getUserName() {
        return userName;
    }
    public double getPrice() {
        return price;
    }
    public long getTimestamp() {
        return timestamp;
    }

    public static List<Order> genOrders(int listLength){
        ArrayList<Order> list = new ArrayList<>(listLength);
        Random rand = new Random();
        int users = listLength/200;// 200 orders per user
        users = users==0 ? listLength : users;
        ArrayList<String> userNames = new ArrayList<>(users);
        for(int i=0; i<users; i++){
            userNames.add(UUID.randomUUID().toString());
        }
        for(int i=0; i<listLength; i++){
            double price = rand.nextInt(1000);
            String userName = userNames.get(rand.nextInt(users));
            list.add(new Order(userName, price, System.nanoTime()));
        }
        return list;
    }
    @Override
    public String toString(){
        return userName + "::" + price;
    }
}

迎接关注我的博客,内里有许多精品合集

  • 本文转载注明出处(必须带毗邻,不能只转文字):字母哥博客

以为对您有辅助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

原创文章,作者:dddof新闻网,如若转载,请注明出处:https://www.dddof.com/archives/22613.html