尽管通过重复“预热”,并且算法增加了一些复杂性,parallelSetAll()
似乎在这里一直变慢。我并不是真的想在这里进行微观基准测试,只是对发生的事情有一种粗略的感觉。
import java.util.*;
import java.time.*;
public class SlowParallelSetAll {
static final int SIZE = 20_000_000;
static long timeIt(Runnable test) {
Instant start = Instant.now();
test.run();
long millis = Duration.between(start, Instant.now()).toMillis();
System.out.println(millis);
return millis;
}
public static void main(String[] args) {
int reps = 10;
long[] la = new long[SIZE];
for(int i = 0; i < reps; i++)
timeIt(() -> Arrays.setAll(la, n -> n * n * 11 + n * 7));
System.out.println("###");
for(int i = 0; i < reps; i++)
timeIt(() -> Arrays.parallelSetAll(la, n -> n * n * 11 + n * 7));
}
}
/* Output:
38
37
35
34
35
34
35
34
34
35
###
52
42
43
44
46
46
44
44
43
43
*/
(lambda表达式)算法应该是独立的,因为它只依赖于索引值n
,因此它看起来应该很容易并行化。
移动呼叫,交替使用两种方法等确实产生了不同的结果,但似乎还有更多的东西,而不仅仅是微基准噪声。首先,我期待正常和并行版本之间的时间差异更大。此外,似乎有人可能会遇到并行版本似乎是正确选择但正常版本实际上更合适的情况。基本上我正在寻找一些有关这方面的见解 - 包括是否有一些简单的方法来表明我所看到的纯粹是一种微观基准现象。
对于它的价值,在这里它被重写为使用System.nanoTime()
并且只是交替测试。这些结果似乎是合理的,尽管整个微基准测试问题令人生畏:
import java.util.*;
import java.time.*;
import java.util.concurrent.*;
public class SlowParallelSetAll {
static final int SIZE = 20_000_000;
static long timeIt(Runnable test) {
long start = System.nanoTime();
test.run();
long delta = System.nanoTime() - start;
long millis = TimeUnit.NANOSECONDS.toMillis(delta);
System.out.println(millis);
return millis;
}
public static void main(String[] args) {
int reps = 10;
long[] la = new long[SIZE];
for(int i = 0; i < reps; i++) {
timeIt(() -> Arrays.parallelSetAll(la, n -> n * n * 11 + n * 7));
timeIt(() -> Arrays.setAll(la, n -> n * n * 11 + n * 7));
}
}
}
/* Output:
41
74
41
73
41
67
40
67
40
67
41
67
41
67
40
67
40
67
40
67
*/
答案 0 :(得分:3)
使用jmh,我得到以下结果(size是数组的长度)。得分是每次调用的运行时间,以微秒为单位(较小=更好)。
Benchmark (size) Mode Cnt Score Error Units
SO34929316.parallelSetAll 1 avgt 20 0.077 ± 0.003 us/op
SO34929316.parallelSetAll 1000 avgt 20 9.935 ± 0.478 us/op
SO34929316.parallelSetAll 100000 avgt 20 56.024 ± 7.008 us/op
SO34929316.parallelSetAll 1000000 avgt 20 518.495 ± 75.331 us/op
SO34929316.parallelSetAll 10000000 avgt 20 5640.574 ± 139.324 us/op
SO34929316.setAll 1 avgt 20 0.016 ± 0.001 us/op
SO34929316.setAll 1000 avgt 20 1.257 ± 0.023 us/op
SO34929316.setAll 100000 avgt 20 116.760 ± 3.116 us/op
SO34929316.setAll 1000000 avgt 20 1168.868 ± 42.153 us/op
SO34929316.setAll 10000000 avgt 20 12347.399 ± 766.931 us/op
正如您所料,parallelSetAll
对于较大的阵列更快,对于较小的阵列则较慢。然而,根据测试(在Win 8.1 / Xeon 2630 v2 / 6核心(x2)上运行),加速因子仅为~x2。
供参考,代码:
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
public class SO34929316 {
@Param({"1", "1000", "100000", "1000000", "10000000"}) int size;
long[] array;
@Setup(Level.Iteration)
public void setup(){
array = new long[size];
}
@Benchmark
public void setAll(Blackhole bh) {
Arrays.setAll(array, n -> n * n * 11 + n * 7);
bh.consume(array);
}
@Benchmark
public void parallelSetAll(Blackhole bh) {
Arrays.parallelSetAll(array, n -> n * n * 11 + n * 7);
bh.consume(array);
}
}