从列表中查找最大元素的java流性能

从列表中查找最大元素的java流性能,java,performance,java-8,java-stream,Java,Performance,Java 8,Java Stream,我编写了一个简单的程序来比较流的性能,以找到整数的最大形式列表。令人惊讶的是,我发现“溪流方式”的性能是“普通方式”的1/10。我做错什么了吗?在哪种情况下,河道是无效的?有人能对这种行为做出很好的解释吗 “流路”耗时80毫秒“常规路”耗时15毫秒 请在下面查找代码 public class Performance { public static void main(String[] args) { ArrayList<Integer> a = new ArrayList

我编写了一个简单的程序来比较流的性能,以找到整数的最大形式列表。令人惊讶的是,我发现“溪流方式”的性能是“普通方式”的1/10。我做错什么了吗?在哪种情况下,河道是无效的?有人能对这种行为做出很好的解释吗

“流路”耗时80毫秒“常规路”耗时15毫秒 请在下面查找代码

public class Performance {

public static void main(String[] args) {

    ArrayList<Integer> a = new ArrayList<Integer>();
    Random randomGenerator = new Random();
    for (int i=0;i<40000;i++){
        a.add(randomGenerator.nextInt(40000));
    }
    long start_s = System.currentTimeMillis( );

            Optional<Integer> m1 = a.stream().max(Integer::compare);

    long diff_s = System.currentTimeMillis( ) - start_s;
    System.out.println(diff_s);


    int e = a.size();
    Integer m = Integer.MIN_VALUE;

    long start = System.currentTimeMillis( );
    for(int i=0; i < e; i++) 
      if(a.get(i) > m) m = a.get(i);

    long diff = System.currentTimeMillis( ) - start;
    System.out.println(diff);


}
公共类性能{
公共静态void main(字符串[]args){
ArrayList a=新的ArrayList();
Random randomGenerator=新的Random();
对于(inti=0;im)m=a.get(i);
long diff=System.currentTimeMillis()-开始;
系统输出打印项次(差异);
}

}

在Java 8中,他们已经投入了大量精力来利用新lambdas的并发进程。您会发现流的速度要快得多,因为列表正在以最有效的方式并发处理,而通常的方式是按顺序运行列表

因为lambda是静态的,这使得线程处理更容易,但是当你在访问硬盘时(逐行读取文件),你可能会发现流没有那么有效,因为硬盘只能访问信息

[更新]
您的流花费的时间比正常方式长得多的原因是因为您先运行。JRE一直在尝试优化性能,因此将以通常的方式设置缓存。如果你先按常规方法跑,然后再按流水方法跑,你会得到相反的结果。我建议在不同的主干中运行测试,以获得最佳结果。

在Java 8中,他们已经投入了大量精力来利用新lambdas的并发进程。您会发现流的速度要快得多,因为列表正在以最有效的方式并发处理,而通常的方式是按顺序运行列表

因为lambda是静态的,这使得线程处理更容易,但是当你在访问硬盘时(逐行读取文件),你可能会发现流没有那么有效,因为硬盘只能访问信息

[更新]
您的流花费的时间比正常方式长得多的原因是因为您先运行。JRE一直在尝试优化性能,因此将以通常的方式设置缓存。如果你先按常规方法跑,然后再按流水方法跑,你会得到相反的结果。我建议在不同的干线上运行测试,以获得最佳结果。

我看到的直接区别是,流方式使用Integer::compare,与循环中的运算符相比,这可能需要更多的自动装箱等。也许您可以在循环中调用Integer::compare,看看这是否是原因

编辑:根据尼古拉斯·罗宾逊的建议,我写了一个新版本的测试。它使用400K大小的列表(原始列表产生的差异结果为零),在两种情况下都使用Integer.compare,并且在每次调用中只运行其中一个(我在两种方法之间选择):

static List a=new ArrayList();
公共静态void main(字符串[]args)
{
Random randomGenerator=新的Random();
对于(int i=0;i<400000;i++){
a、 增加(randomGenerator.nextInt(400000));
}
长启动=System.currentTimeMillis();
//整数max=checkLoop();
整数max=checkStream();
long diff=System.currentTimeMillis()-开始;
系统输出打印项次(“最大”+最大+“差异”+差异);
}
静态整数校验流()
{
可选的max=a.stream().max(整数::比较);
返回max.get();
}
静态整数checkLoop()
{
int e=a.size();
整数最大值=整数最小值;
for(int i=0;i0)max=a.get(i);
}
返回最大值;
}
循环的结果:
max 399999 diff 10


流的结果:
max 399999 diff 40
(有时我得到了
50

我看到的直接区别是流方式使用Integer::compare,与循环中的运算符相比,它可能需要更多的自动装箱等。也许您可以在循环中调用Integer::compare,看看这是否是原因

编辑:根据尼古拉斯·罗宾逊的建议,我写了一个新版本的测试。它使用400K大小的列表(原始列表产生的差异结果为零),在两种情况下都使用Integer.compare,并且在每次调用中只运行其中一个(我在两种方法之间选择):

static List a=new ArrayList();
公共静态void main(字符串[]args)
{
Random randomGenerator=新的Random();
对于(int i=0;i<400000;i++){
a、 增加(randomGenerator.nextInt(400000));
}
长启动=System.currentTimeMillis();
//整数max=checkLoop();
整数max=checkStream();
long diff=System.currentTimeMillis()-开始;
系统输出打印项次(“最大”+最大+“差异”+差异);
}
静态整数校验流()
{
可选的max=a.stream().max(整数::比较);
返回max.get();
}
静态整数checkLoop()
{
int e=a.size();
整数最大值=整数最小值;
for(int i=0;i0)max=a.get(i);
}
返回最大值;
}
循环的结果:
max 399999 diff 10


流的结果:
max 399999 diff 40
(有时我得到
50

是的,对于这样简单的操作,流速度较慢。但你的数字完全不相关。如果您认为15毫秒对于您的任务来说是令人满意的时间,那么有一个好消息:预热后的流代码可以在大约0.1-0.2毫秒内解决这个问题,这是速度的70-150倍

以下是快速而肮脏的基准:

import java.util.concurrent.TimeUnit;
import java.util.*;
import java.util.stream.*;

import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.annotations.*;

@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(3)
@State(Scope.Benchmark)
public class StreamTest {
    // Stream API is very nice to get random data for tests!
    List<Integer> a = new Random().ints(40000, 0, 40000).boxed()
                                  .collect(Collectors.toList());

    @Benchmark
    public Integer streamList() {
        return a.stream().max(Integer::compare).orElse(Integer.MIN_VALUE);
    }

    @Benchmark
    public Integer simpleList() {
        int e = a.size();
        Integer m = Integer.MIN_VALUE;
        for(int i=0; i < e; i++) 
            if(a.get(i) > m) m = a.get(i);
        return m;
    }
}
这里是微秒。所以流版本实际上要快得多
import java.util.concurrent.TimeUnit;
import java.util.*;
import java.util.stream.*;

import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.annotations.*;

@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(3)
@State(Scope.Benchmark)
public class StreamTest {
    // Stream API is very nice to get random data for tests!
    List<Integer> a = new Random().ints(40000, 0, 40000).boxed()
                                  .collect(Collectors.toList());

    @Benchmark
    public Integer streamList() {
        return a.stream().max(Integer::compare).orElse(Integer.MIN_VALUE);
    }

    @Benchmark
    public Integer simpleList() {
        int e = a.size();
        Integer m = Integer.MIN_VALUE;
        for(int i=0; i < e; i++) 
            if(a.get(i) > m) m = a.get(i);
        return m;
    }
}
Benchmark               Mode  Cnt    Score    Error  Units
StreamTest.simpleList   avgt   30   38.241 ±  0.434  us/op
StreamTest.streamList   avgt   30  215.425 ± 32.871  us/op
int[] b = new Random().ints(40000, 0, 40000).toArray();

@Benchmark
public int streamArray() {
    return Arrays.stream(b).max().orElse(Integer.MIN_VALUE);
}

@Benchmark
public int simpleArray() {
    int e = b.length;
    int m = Integer.MIN_VALUE;
    for(int i=0; i < e; i++) 
        if(b[i] > m) m = b[i];
    return m;
}
Benchmark               Mode  Cnt    Score    Error  Units
StreamTest.simpleArray  avgt   30   10.132 ±  0.193  us/op
StreamTest.streamArray  avgt   30  167.435 ±  1.155  us/op
Integer max = Collections.max(a);