我无法确定并行运行计时器的问题

时间:2015-08-07 17:58:53

标签: java concurrency timer parallel-processing fork

我有一个程序,将中值过滤器应用于超过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()处理起始数组中lohi索引之间的值,并将处理后的值添加到相同位置的最终数组中。这就是left.join()之后没有数组合并的原因。

我的运行时间对于并行而言非常快 - 我认为我的计时器或我的left.join()语句一定有问题。对于顺序使用大小为3的过滤窗口和并行的0.004毫秒,我的平均时间约为170毫秒。为什么我会得到这些价值?我特别担心我的join()位置错误。

如果您想查看我的整个代码,包括所有类和一些输入文件,follow this link

1 个答案:

答案 0 :(得分:0)

在对代码进行一些测试后,我找到了原因。事实证明,ForkJoinPool只运行一次任务实例。使用相同任务实例的后续invoke()调用将立即返回。因此,您必须为每次运行重新执行该任务。

另一个问题是并行(标准线程)运行。您正在开始线程,但在测量时间之前从不等待它们完成。我想你可以在这里使用CyclicBarrier。

通过上述修复,我获得了ForkJoin和标准线程大致相同的时间。它比连续快三倍。似乎是合理的。

P.S。你正在做一个微观基准。阅读该问题的答案以提高基准准确度可能很有用:How do I write a correct micro-benchmark in Java?