Java 为什么并行矩阵加法如此低效?
我对多线程非常陌生,没有太多使用内部类的经验 任务是以并行方式添加两个包含双值的矩阵 我的想法是递归地这样做,将大矩阵分解成小矩阵,当矩阵达到一定的大小限制时执行加法,然后融合它们 并行化代码的运行速度比序列化代码慢40-80倍 我怀疑我在这里做错了什么。也许是因为我创建了很多新矩阵,或者是因为我遍历了很多次 代码如下:Java 为什么并行矩阵加法如此低效?,java,multithreading,optimization,matrix,concurrency,Java,Multithreading,Optimization,Matrix,Concurrency,我对多线程非常陌生,没有太多使用内部类的经验 任务是以并行方式添加两个包含双值的矩阵 我的想法是递归地这样做,将大矩阵分解成小矩阵,当矩阵达到一定的大小限制时执行加法,然后融合它们 并行化代码的运行速度比序列化代码慢40-80倍 我怀疑我在这里做错了什么。也许是因为我创建了很多新矩阵,或者是因为我遍历了很多次 代码如下: package concurrency; import java.util.Random; import java.util.concurrent.ForkJoinPool;
package concurrency;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ParallelMatrixAddition {
public static void main(String[] args) {
Random rand = new Random();
final int SIZE = 1000;
double[][] one = new double[SIZE][SIZE];
double[][] two = new double[SIZE][SIZE];
double[][] serialSums = new double[SIZE][SIZE];
double[][] parallelSums = new double[SIZE][SIZE];
for (int i = 0; i < one.length; i++) {
for (int j = 0; j < one.length; j++) {
one[i][j] = rand.nextDouble();
two[i][j] = rand.nextDouble();
}
}
long serialStartTime = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
serialSums[i][j] = one[i][j] + two[i][j];
}
}
long serialEndTime = System.currentTimeMillis();
System.out.println("Serial runtime is: " + (serialEndTime - serialStartTime) + " milliseconds");
long startTime = System.currentTimeMillis();
parallelSums = parallelAddMatrix(one, two);
long endTime = System.currentTimeMillis();
System.out.println("Parallel execution took " + (endTime - startTime) + " milliseconds.");
}
public static double[][] parallelAddMatrix(double[][] a, double[][] b) {
RecursiveTask<double[][]> task = new SumMatricesTask(a, b);
ForkJoinPool pool = new ForkJoinPool();
double[][] result = new double[a.length][a.length];
result = pool.invoke(task);
return result;
}
@SuppressWarnings("serial")
private static class SumMatricesTask extends RecursiveTask<double[][]> {
private final static int THRESHOLD = 200;
private double[][] sumz;
private double[][] one;
private double[][] two;
public SumMatricesTask(double[][] one, double[][] two) {
this.one = one;
this.two = two;
this.sumz = new double[one.length][one.length];
}
@Override
public double[][] compute() {
if (this.one.length < THRESHOLD) {
// Compute a sum here.
// Add the sums of the matrices and store the result in the
// matrix we will return later.
double[][] aStuff = new double[this.one.length][this.one.length];
for (int i = 0; i < one.length; i++) {
for (int j = 0; j < one.length; j++) {
aStuff[i][j] = this.one[i][j] + this.two[i][j];
}
}
return aStuff;
} else {
// Split a matrix into four smaller submatrices.
// Create four forks, then four joins.
int currentSize = this.one.length;
int newSize = currentSize / 2;
double[][] topLeftA = new double[newSize][newSize];
double[][] topLeftB = new double[newSize][newSize];
double[][] topLeftSums = new double[newSize][newSize];
double[][] topRightA = new double[newSize][newSize];
double[][] topRightB = new double[newSize][newSize];
double[][] topRightSums = new double[newSize][newSize];
double[][] bottomLeftA = new double[newSize][newSize];
double[][] bottomLeftB = new double[newSize][newSize];
double[][] bottomLeftSums = new double[newSize][newSize];
double[][] bottomRightA = new double[newSize][newSize];
double[][] bottomRightB = new double[newSize][newSize];
double[][] bottomRightSums = new double[newSize][newSize];
// Populate topLeftA and topLeftB
for (int i = 0; i < newSize; i++) {
for (int j = 0; j < newSize; j++) {
topLeftA[i][j] = this.one[i][j];
topLeftB[i][j] = this.two[i][j];
}
}
// Populate bottomLeftA and bottomLeftB
for (int i = 0; i < newSize; i++) {
for (int j = 0; j < newSize; j++) {
bottomLeftA[i][j] = this.one[i + newSize][j];
bottomLeftB[i][j] = this.two[i + newSize][j];
}
}
// Populate topRightA and topRightB
for (int i = 0; i < newSize; i++) {
for (int j = 0; j < newSize; j++) {
topRightA[i][j] = this.one[i][j + newSize];
topRightB[i][j] = this.two[i][j + newSize];
}
}
// Populate bottomRightA and bottomRightB
for (int i = 0; i < newSize; i++) {
for (int j = 0; j < newSize; j++) {
bottomRightA[i][j] = this.one[i + newSize][j + newSize];
bottomRightB[i][j] = this.two[i + newSize][j + newSize];
}
}
SumMatricesTask topLeft = new SumMatricesTask(topLeftA, topLeftB);
SumMatricesTask topRight = new SumMatricesTask(topRightA, topRightB);
SumMatricesTask bottomLeft = new SumMatricesTask(bottomLeftA, bottomLeftB);
SumMatricesTask bottomRight = new SumMatricesTask(bottomRightA, bottomRightB);
topLeft.fork();
topRight.fork();
bottomLeft.fork();
bottomRight.fork();
topLeftSums = topLeft.join();
topRightSums = topRight.join();
bottomLeftSums = bottomLeft.join();
bottomRightSums = bottomRight.join();
// Fuse the four matrices into one and return it.
for (int i = 0; i < newSize; i++) {
for (int j = 0; j < newSize; j++) {
this.sumz[i][j] = topLeftSums[i][j];
}
}
for (int i = newSize; i < newSize * 2; i++) {
for (int j = 0; j < newSize; j++) {
this.sumz[i][j] = bottomLeftSums[i - newSize][j];
}
}
for (int i = 0; i < newSize; i++) {
for (int j = newSize; j < newSize * 2; j++) {
this.sumz[i][j] = topRightSums[i][j - newSize];
}
}
for (int i = newSize; i < newSize * 2; i++) {
for (int j = newSize; j < newSize * 2; j++) {
this.sumz[i][j] = bottomRightSums[i - newSize][j - newSize];
}
}
return this.sumz;
}
}
}
包并发;
导入java.util.Random;
导入java.util.concurrent.ForkJoinPool;
导入java.util.concurrent.RecursiveTask;
公共类并行矩阵加法{
公共静态void main(字符串[]args){
Random rand=新的Random();
最终整数大小=1000;
双精度[]一=新的双精度[尺寸][尺寸];
double[]two=新的double[SIZE][SIZE];
double[]serialSums=新的double[SIZE][SIZE];
double[]parallelSums=新的double[SIZE][SIZE];
for(int i=0;i<1.length;i++){
对于(int j=0;j<1.length;j++){
一[i][j]=rand.nextDouble();
二[i][j]=rand.nextDouble();
}
}
long serialStartTime=System.currentTimeMillis();
对于(int i=0;i