并行中值滤波器

所以我一直在研究中值滤波器*(比较顺序到并行,因为我正在学习如何并发编码),但是并行版本无限期地运行以获得大输入(大约100k;它运行得更好)。

实质上,代码接收文件,在给定特定窗口大小的情况下对其进行过滤,然后将其写入新文件。 并行编程的新手,所以当我遇到可能出错的问题时,我有点迷失。

//import everything public class SecondMedianFilter extends RecursiveAction { float[] numbers; static int filter; int window; int length; int lo; int hi; static final int SEQUENTIAL_CUTOFF = 500; float[] outArray; public SecondMedianFilter(float[] numbers, int filter, int lo, int hi) { this.numbers = numbers; this.filter = filter; this.lo = lo; this.hi = hi; length = numbers.length; window = (filter - 1) / 2; } public float[] getRes() { return result; } protected void compute() { result = new float[length]; if ((hi - lo) < SEQUENTIAL_CUTOFF) { for (int a = lo; a < hi; a++) { for (int i = 0; i < length; i++) { if (i = length - window) { result[i] = numbers[i]; } else { float[] subArray = Arrays.copyOfRange(numbers, i - window, i + window + 1); Arrays.sort(subArray); float median = subArray[(subArray.length / 2)]; result[i] = median; } } } } else { SecondMedianFilter left = new SecondMedianFilter(filtered, filter, lo, (hi + lo) / 2); SecondMedianFilter right = new SecondMedianFilter(filtered, filter, (hi + lo) / 2, hi); left.fork(); right.compute(); left.join(); } } public static void main(String[] args) { //reads in a file, processes each line into an array of floats that // I call inArray, which gets filtered into outIntArray float[] outIntArray = new float[inArray.length]; if (window  21 || window % 2 == 0) { System.out.println("Window size error."); } else { SecondMedianFilter smf = new SecondMedianFilter(inArray, window, 0, inArray.length); smf.compute(); outIntArray = smf.getRes(); // loops through outIntArray and writes to file. }//end main } } 

按顺序执行它似乎工作(大约1 000 000个元素在一秒钟内),然而我的并发版本只需要4个就可以完成10 000个元素。 正如我所说,并行编程的全新,所以我很丢失。 有没有一种方法可以并行执行中值滤波器,而我却缺少这种方法?

(*中位数filter=获取数组的某个窗口,对它们进行排序并将该索引处的原始元素替换为已排序子数组的中位数;例如:2,80,6,3,1结果为2,6 ,6,3,1。)

*例如:

 Taking in this file: 5.0 13.2 -2.6 22.3 12.4 -0.21 23.1 -0.2454 

它将读入数组[5.0,13.2,-2.6,22.3,12.4,-0.21,23.1,-0.2454]窗口大小,比如说3.为了适用于过滤,元素必须具有在它之前的n个元素和在它之后的n个元素,其中n =(window-1)/ 2; 因此,在window = 3的情况下,元素必须在其两侧具有1个元素。 如果它不满足该条件,则该元素按原样使用。

因此5.0将保留,因为它之前没有元素。 但是13.2满足条件 – 因此,采用子arrays[5.0,13.2,-2.6]。 然后对该数组进行排序(使用.sort():[ – 6.2,5.0,13.2]),然后将中位数设为5.0。 13.2随后在最终数组中替换为5.0,现在看起来像[5.0,5.0,…]。

接下来它移动到-2.6 – 它有一个前面的元素和一个后面的元素,所以子数组[-2.6,22.3,12.4]被采集,排序,并且中间值12.4被添加到最终数组:[5.0, 5.0,12.4,……]。 它重复此过程,直到访问了原始数组中的所有元素。 然后它将最终数组写入文件,但这并不是特别相关(除非这可以以某种方式并行完成 – 我怀疑,但正如我所说:完成noob在这里)。

你的处理完全是平行的。 实际上,您可以为每个元素子集计算中值滤波器 (因为您不会在计算中更改原始数组的内容)。 所以,是的,你可以并行完成。

说这个,即使我不知道RecursiveAction的所有细节,我会说你错过了整个线程部分。 我检查了一下,任何递归操作都应该由ForkJoinPool类调用。 然后这个处理线程并fork / join它们。

此外,在左右分割操作(使用两个不同的调用)需要您稍后分叉加入它们。

我希望这样的东西有一个有效的配置:

 public class SecondMedianFilter extends RecursiveAction { ... protected void compute() { result = new float[length]; if ((hi - lo) < SEQUENTIAL_CUTOFF) { for (int a = lo; a < hi; a++) { for (int i = 0; i < length; i++) { if (i < window || i >= length - window) { result[i] = numbers[i]; } else { float[] subArray = Arrays.copyOfRange(numbers, i - window, i + window + 1); Arrays.sort(subArray); float median = subArray[(subArray.length / 2)]; result[i] = median; } } } } else { SecondMedianFilter left = new SecondMedianFilter(filtered, filter, lo, (hi + lo) / 2); SecondMedianFilter right = new SecondMedianFilter(filtered, filter, (hi + lo) / 2, hi); left.fork(); //CODE CHANGES FROM HERE right.fork(); //right.compute(); <- IS IMPLICIT IN THE FORK left.join(); right.join(); //TO HERE } } public static void main(String[] args) { //reads in a file, processes each line into an array of floats that // I call inArray, which gets filtered into outIntArray float[] outIntArray = new float[inArray.length]; if (window < 3 || window > 21 || window % 2 == 0) { System.out.println("Window size error."); } else { // CODE CHANGES FROM HERE ForkJoinPool pool = new ForkJoinPool(); // WHO HANDLES THE THREADS SecondMedianFilter smf = new SecondMedianFilter(inArray, window, 0, inArray.length); //smf.compute(); <- DUTY OF THREAD POOL pool.invoke(smf); // START OF PROCESSING outIntArray = smf.getRes(); // loops through outIntArray and writes to file. }//end main } 

}

我将为您提供两个链接,他们将详细解释整个过程的工作原理(其中一个显示并行和顺序方法)。

http://www.concretepage.com/java/jdk7/example-of-recursiveaction-in-java

http://www.logicbig.com/how-to/java/fork-and-join-recursive-action/

编辑我没有检查你的算法是如何工作的(我希望它将数组拆分为两个,直到绑定到一个绑定的情况),所以我只是根据你写的内容添加了一些代码。