How do I write a correct micro-benchmark in Java? (11个答案)
Java 8: performance of Streams vs Collections (4个答案)
Java lambdas 20 times slower than anonymous classes (1个答案)
去年关闭。
我只是尝试了一个关于codility的测试示例。任务是:“...给定一个由N个整数组成的数组A,返回在A中不出现的最小正整数(大于0)。”
加:
N是[1..100,000]范围内的整数; 数组A的每个元素都是[-1,000,000..1,000,000]范围内的整数。 我的尝试是典型的Java 8解决方案:
public int solution(int[] A) {
Set<Integer> l = Arrays
.stream(A)
.boxed()
.filter(i -> i > 0)
.collect(Collectors.toSet());
return IntStream
.iterate(1, a -> a + 1)
.filter(i -> !l.contains(i))
.findFirst()
.getAsInt();
}
都正确,但是中间大小测试数组的测试超时。
第二次尝试(纯旧Java):
public int solution(int[] A) {
boolean[] B = new boolean[1000001];
for (int a : A) {
if (a > 0) {
B[a] = true;
}
}
for (int i = 1; i <= 1000000; i++) {
if (!B[i]) {
return i;
}
}
return 1;
}
这个版本的速度快得惊人,特别是对于短数组A。
问题:
我第一次尝试时是否缺少某些东西? 有调整选项吗? 对Codility的测试是否为时过早,并且实际上,这种差异有望几乎全部消失? 有谁有更好的Java 8解决方案? 测试结果第一版:▶example1
第一个示例测试✔确定
1. 0.108 s OK
▶example2
第二个示例测试✔OK
1. 0.104 s OK
▶example3
第三例测试✔确定
1. 0.104 s OK
▶Extreme_Single
单个元素✔确定
1. 0.100秒
2. 0.104 s OK
3. 0.104 s OK
4. 0.100 s OK
▶简单
简单测试✔确定
1. 0.100秒
2. 0.104 s OK
3. 0.100 s OK
▶extreme_min_max_value
最小和最大值✔确定
1. 0.100秒
2. 0.104 s OK
▶positive_only
依次从0 ... 100到102 ... 200的顺序排序
1. 0.100秒
2. 0.104 s OK
▶negative_only
随机播放的序列-100 ... -1✔确定
1. 0.100秒
▶中
混沌序列长度= 10005(带负号)✘超时错误
运行时间:0.136秒,时间限制:0.100秒。
1. 0.136 s超时错误,运行时间:0.136秒,时间限制:0.100秒。
2. 0.128 s超时错误,运行时间:0.128秒,时间限制:0.100秒。
3. 0.144 s超时错误,运行时间:0.144秒,时间限制:0.128秒。
▶大_1
混沌+序列1,2,...,40000(无负号)✔OK
1. 0.588 s OK
▶大_2
随机播放顺序1,2,...,100000(无负号)✔OK
1. 0.748 s OK
2. 0.660 s OK
▶大3
混沌+许多-1,1,2,3(带减号)✔OK
1. 0.444 s OK
测试结果第二版:▶example1
第一个示例测试✔确定
1. 0.004 s OK
▶example2
第二个示例测试✔OK
1. 0.004 s OK
▶example3
第三例测试✔确定
1. 0.004 s OK
▶Extreme_Single
单个元素✔确定
1. 0.004 s OK
2. 0.008 s OK
3. 0.004 s OK
4. 0.008 s OK
▶简单
简单测试✔确定
1. 0.004 s OK
2. 0.004 s OK
3. 0.008秒OK
▶extreme_min_max_value
最小和最大值✔确定
1. 0.008 s OK
2. 0.004 s OK
▶positive_only
依次从0 ... 100到102 ... 200的顺序排序
1. 0.008 s OK
2. 0.004 s OK
▶negative_only
随机播放的序列-100 ... -1✔确定
1. 0.008 s OK
▶中
混沌序列长度= 10005(带减号)✔确定
1. 0.024 s OK
2. 0.024 s OK
3. 0.032 s OK
▶大_1
混沌+序列1,2,...,40000(无负号)✔OK
1. 0.220 s OK
▶大_2
随机播放顺序1,2,...,100000(无负号)✔OK
1. 0.244 s OK
2. 0.244 s OK
▶大3
混沌+许多-1,1,2,3(带减号)✔OK
1. 0.172 s OK
底线:尤其是使用小型Java数组的小型数组的测试要快两个数量级。对于大型阵列,其“仅”系数为3。
编辑:根据评论,我只是想更深入地研究问题并尝试:
public int solution(int[] A) {
boolean[] B = new boolean[1000001];
for (int a : A) {
if (a>0){
B[a] = true;
}
}
return IntStream
.iterate(1, a -> a + 1)
.filter(i -> !B[i])
.findFirst()
.getAsInt();
}
结果:▶example1
第一个示例测试✔确定
1. 0.096 s OK
▶example2
第二个示例测试✔OK
1. 0.096 s OK
▶example3
第三例测试✔确定
1. 0.096 s OK
折叠所有正确性测试
▶Extreme_Single
单个元素✔确定
1. 0.096 s OK
2. 0.096 s OK
3. 0.096 s OK
4. 0.096 s OK
▶简单
简单测试✔确定
1. 0.100秒
2. 0.096 s OK
3. 0.100 s OK
▶extreme_min_max_value
最小和最大值✔确定
1. 0.096 s OK
2. 0.100 s OK
▶positive_only
依次从0 ... 100到102 ... 200的顺序排序
1. 0.096 s OK
2. 0.096 s OK
▶negative_only
随机播放的序列-100 ... -1✔确定
1. 0.096 s OK
折叠所有性能测试
▶中
混沌序列长度= 10005(带负号)✘超时错误
运行时间:0.116秒,时间限制:0.112秒。
1. 0.116 s超时错误,运行时间:0.116秒,时间限制:0.112秒。
2. 0.116 s超时错误,运行时间:0.116秒,时间限制:0.100秒。
3. 0.124 s OK
▶大_1
混沌+序列1,2,...,40000(无负号)✔OK
1. 0.340 s OK
▶大_2
随机播放顺序1,2,...,100000(无负号)✔OK
1. 0.408 s OK
2. 0.372 s OK
▶大3
混沌+许多-1,1,2,3(带减号)✔OK
1. 0.272 s OK
结论:对于小型测试数组,它几乎与第一个版本一样慢,因此在这里IntStream似乎是瓶颈。 对于大型测试阵列,速度似乎是中等的。因此,我不太确定它应该告诉我什么。 编辑2:我实际上只是找到了一篇描述该问题的文章:
https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html。其中,作者声称流之间的区别以及在数组上运行的for循环的原因是流是相当新的事实。但是,这篇文章的日期是4年前。