我有一个程序,将中值过滤器应用于超过200万个值的数组。
我正在尝试比较同一数据集上顺序与并行的运行时间。因此,当我执行程序时,它会执行20次运行,每次运行都会计时,并且平均20次输出到控制台。
ArrayList<Double> times = new ArrayList<>(20);//to calculate average run time
for (int run = 1; run < 21; run++) //algorithm will run 20 times
{
long startTime = System.nanoTime();
switch (method)
{
case 1: //Sequential
filt.seqFilter();
break;
case 2: //ForkJoin Framework
pool.invoke(filt); //pool is ForkJoin
break;
}
Double timeElapsed = (System.nanoTime() - startTime) / 1000000.0;
times.add(run - 1, timeElapsed);
System.out.println("Run " + run + ": " + timeElapsed + " milliseconds.");
}
times.remove(Collections.max(times)); //there's always a slow outlier
double timesSum = 0;
for (Double e : times)
{
timesSum += e;
}
double average = timesSum / 19;
System.out.println("Runtime: " + average);
filt
的类型为FilterObject
,其范围为RecursiveAction
。我在compute()
中覆盖的FilterObject
方法如下所示:
public void compute()
{
if (hi - lo <= SEQUENTIAL_THRESHOLD)
{
seqFilter();
}
else
{
FilterObject left = new FilterObject(lo, (hi + lo) / 2);
FilterObject right = new FilterObject((hi + lo) / 2, hi);
left.fork();
right.compute();
left.join();
}
}
seqFilter()
处理起始数组中lo
和hi
索引之间的值,并将处理后的值添加到相同位置的最终数组中。这就是left.join()
之后没有数组合并的原因。
我的运行时间对于并行而言非常快 - 我认为我的计时器或我的left.join()
语句一定有问题。对于顺序使用大小为3的过滤窗口和并行的0.004毫秒,我的平均时间约为170毫秒。为什么我会得到这些价值?我特别担心我的join()
位置错误。
如果您想查看我的整个代码,包括所有类和一些输入文件,follow this link。
答案 0 :(得分:0)
在对代码进行一些测试后,我找到了原因。事实证明,ForkJoinPool只运行一次任务实例。使用相同任务实例的后续invoke()调用将立即返回。因此,您必须为每次运行重新执行该任务。
另一个问题是并行(标准线程)运行。您正在开始线程,但在测量时间之前从不等待它们完成。我想你可以在这里使用CyclicBarrier。
通过上述修复,我获得了ForkJoin和标准线程大致相同的时间。它比连续快三倍。似乎是合理的。
P.S。你正在做一个微观基准。阅读该问题的答案以提高基准准确度可能很有用:How do I write a correct micro-benchmark in Java?