导读:
笔者使用的是小米笔记本 1.99 GHz 四核Intel Core i7,本文对比了几种方法求素数耗时。这几种方法分别是:传统的for方法,java8 stream流,parallel stream。结果表明stream性能通常差一点,但是写法更简洁,世间安得双全法,不负如来不负卿?parallel stream,充分利用多核性能吧!!!
Stream
Java8 增加了重要的特性是Stream流。stream的使用可以将代码中大量的for循环变为一系列简洁的高阶函数操作。
1.8以前要收集一个业务对象DTO的列表中的某个业务对象字段,我们需要这样写:
List<Integer> list = new ArrayList<>(timeConsumptionList.size());
for (TimeConsumption timeConsumption : timeConsumptionList) {
list.add(timeConsumption.getN());
}
现在可以这样写了
List<Integer> nList = timeConsumptionList.stream()
.map(TimeConsumption::getN)
.collect(Collectors.toList());
正题
好了。不说废话了,切入正题,上比较代码。
package lambdasinaction.chap6;
import com.google.gson.Gson;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
/**
* @author chuanyi@88.com
* @date 2020/8/14
* @Description
*/
public class NotePad {
public static void main(String[] args) {
//输出(2 -> n)的 素数
int n = 10;
List<TimeConsumption> timeConsumptionList = new ArrayList<>();
for (int i = 0; i < 6; i++) {
TimeConsumption timeConsumption = new TimeConsumption();
timeConsumption.setN(n);
Time time = new Time();
findPrimeByTraditional(n,time);
findPrimeByStream(n,time);
findPrimeByParallelStream(n,time);
timeConsumption.setTime(time);
timeConsumptionList.add(timeConsumption);
n *= 10;
}
System.out.println(new Gson().toJson(timeConsumptionList));
}
@Data
public static class TimeConsumption implements Serializable {
private int n;
private Time time;
}
@Data
public static class Time implements Serializable{
private int streamTime;
private int parallelStreamTime;
private int traversalTime;
}
private static void findPrimeByTraditional(int n,Time time) {
long start2 = System.currentTimeMillis();
findPrimeNumbers(n);
int cost = (int) (System.currentTimeMillis() - start2);
time.setTraversalTime(cost);
System.out.println("cost by traditional method:" + cost + " ms");
}
private static void findPrimeByParallelStream(int n,Time time) {
long start = System.currentTimeMillis();
IntStream.iterate(2, i -> i < n, i -> i + 1).parallel().filter(NotePad::isPrime).forEach(System.out::println);
int cost = (int) (System.currentTimeMillis() - start);
time.setParallelStreamTime(cost);
System.out.println("parallel stream cost :" + cost + " ms");
}
private static void findPrimeByStream(int n,Time time) {
long start = System.currentTimeMillis();
IntStream.iterate(2, i -> i < n, i -> i + 1).filter(NotePad::isPrime).forEach(System.out::println);
int cost = (int) (System.currentTimeMillis() - start);
time.setStreamTime(cost);
System.out.println("stream cost :" + cost + " ms");
}
private static void findPrimeNumbers(int i) {
for (int j = 2; j < i; j++) {
if (isAPrime(j)) {
System.out.println(j);
}
}
}
public static boolean isAPrime(int n) {
int sqrt = (int) Math.sqrt(n);
for (int i = 2; i <= sqrt; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static boolean isPrime(int n) {
int sqrt = (int) Math.sqrt(n);
return IntStream.iterate(2, i -> i <= sqrt, i -> i + 1).parallel().noneMatch(i -> n % i == 0);
}
}
更直观的折线图
综述
传统的for方法性能还是十分给力的,但是代码太长了,人生苦短,效果和工作量一定要权衡好,差不多的表现情况下,如果对实际业务无明显影响,当然选择更简洁的方法。stream性能太差了,在数据较少的情况下和for的差距不值一提,但是数据量上来以后,就差太多了,小老弟,你咋这么不给力呢。相比于不争气的stream,parallel stream表现还是相当不错的,而且还保留了stream的简洁性,正所谓青出于蓝而胜于蓝。但是在大规模数据面前,和最原始的for也还有一些差距。但是日常使用中如果没有这么大的数据量使用stream就可以了。
后记
其实求素数这里不用每次都求出来,可以求一次最大范围的素数,保留下来用作取模的除数,这样就能大大加快计算了。周末愉快~~