问题描述
我有一个程序,将中值过滤器应用于超过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
。
我在FilterObject
重写的compute()
方法如下所示:
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()
语句一定有问题。
连续的平均时间约为170毫秒,而过滤窗口的大小为3,并行的平均为0.004毫秒。
为什么我得到这些值?
我特别担心我的join()
放在错误的位置。
如果您想查看我的完整代码,包括所有类和一些输入文件,请 。
1楼
对您的代码进行一些测试后,我找到了原因。 事实证明,ForkJoinPool仅运行一个任务实例一次。 具有相同任务实例的后续invoke()调用将立即返回。 因此,您必须在每次运行时重新实例化该任务。
另一个问题是并行(标准线程)运行。 您正在启动线程,但是从不等待它们完成才测量时间。 我认为您可以在此处使用CyclicBarrier。
使用上述修复程序,我可以获得与ForkJoin和标准线程大致相同的时间。 而且它比顺序速度快三倍。 似乎合理。
PS:您正在做一个微基准测试。 阅读该问题的答案以提高基准精度可能会很有用: