【发布时间】:2020-02-20 23:17:04
【问题描述】:
我正在尝试用多个线程实现矩阵乘法。一切似乎都正常工作,但是,它的工作速度比通常的算法慢得多。这是我的代码
public class Main {
private static int nRows = 500; //number of rows and columns in matrices
private static int[][] matrix1 = new int[nRows][nRows]; //first matrix for multiplication
private static int[][] matrix2 = new int[nRows][nRows]; //second matrix for multiplication
private static int[][] result1 = new int[nRows][nRows]; //result from linear matrix multiplication
private static int[][] result2 = new int[nRows][nRows]; //result from parallel matrix multiplication
private static Thread[][] pool = new Thread[nRows][nRows]; //array of threads
//method used for transposing a matrix to get its column easily
public static int[][] transpose(int[][] matrix) {
int[][] newMatrix = new int[matrix[0].length][matrix.length];
for (int i = 0; i < matrix[0].length; i++) {
for (int j = 0; j < matrix.length; j++) {
newMatrix[i][j] = matrix[j][i];
}
}
return newMatrix;
}
public static void main(String[] args) {
//initializing input matrices (setting all elements = 1)
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nRows; j++) {
matrix1[i][j] = 1;
matrix2[i][j] = 1;
}
}
long start;
long end;
System.out.println("Linear algorithm");
start = System.currentTimeMillis();
//linear multiplication algorithm
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nRows; j++) {
int temp = 0;
for (int k = 0; k < nRows; k++) {
temp += matrix1[i][k] * matrix2[k][j];
}
result1[i][j] = temp;
}
}
//show result
// for(int i=0;i<nRows;i++){
// for(int j=0;j<nRows;j++){
// System.out.print(result1[i][j] + " ");
// }
// System.out.println();
// }
end = System.currentTimeMillis();
System.out.println("Time with linear algorithm: " + (end - start));
//--------------------
System.out.println("Parallel algorithm");
start = System.currentTimeMillis();
int[][] matrix3 = transpose(matrix2); //get a transpose copy of second matrix
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nRows; j++) {
pool[i][j] = new myThread(matrix1[i], matrix3[j], i, j); //creating a thread for each element
pool[i][j].start(); //starting a thread
}
}
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nRows; j++) {
try {
pool[i][j].join(); //waiting for the thread to finish its job
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//show the result
// for(int i=0;i<nRows;i++){
// for(int j=0;j<nRows;j++){
// System.out.print(result2[i][j] + " ");
// }
// System.out.println();
// }
end = System.currentTimeMillis();
System.out.println("Time with parallel algorithm: " + (end - start));
}
//class, where parallel multiplication is implemented
private static class myThread extends Thread {
private int[] row = new int[nRows]; //row for multiplication
private int[] col = new int[nRows]; //column for multiplication
private int i; //row index of the element in resulting matrix
private int j; //column index of the element in resulting matrix
//constructor
public myThread(int[] r, int[] c, int i, int j) {
row = r;
col = c;
this.i = i;
this.j = j;
}
public void run() {
int temp = 0;
for (int k = 0; k < nRows; k++) {
temp += row[k] * col[k]; //getting the element by multiplying row and column of two matrices
}
result2[i][j] = temp; //writing the resulting element to the resulting matrix
}
}
}
在这里,我为结果矩阵中的每个元素创建一个新线程。我将这些线程写入一个数组,启动它们,最后等待它们完成工作。我已经看到了一些实现,其中整个输入矩阵(它们都是)将作为参数提供给线程。然而,我的任务是提出一种算法,其中只给出一行和一列(对于这个特定元素是必需的)。
测量经过的时间后,我得到以下结果
Linear algorithm
Time with linear algorithm: 557
Parallel algorithm
Time with parallel algorithm: 38262
我做错了什么?提前致谢!
【问题讨论】:
-
一些观察:1) 由于首先发生并行性需要开销,并行操作实际上最终变慢是很常见的。 2) 在 Java 中测量任何东西的性能要比对
System.currentTimeMillis()进行两次调用的差异要复杂得多。 stackoverflow.com/q/504103/869736 -
使用并发对于阻塞 I/O 操作(如写入磁盘、调用数据库或 Web 服务)很有用,您所做的只是乘法,您必须考虑是否创建一个全新的线程(单次乘法)是值得的
-
您正在为 500x500 矩阵中的每个元素启动一个线程?那么,25,000 个线程?我并不惊讶它变慢了。在具有 25,000 个内核和 1 TB 内存的机器上试一试。或者,更好的是,使用线程池执行器,其线程数与内核数一样多,并为其提供任务以进行单独的乘法运算。
-
尝试注释掉并行实现中的所有乘法逻辑并再次运行它,您会注意到绝大多数时间只是在旋转所有线程。
-
让每个线程处理(例如,矩阵的一行)可能会更好,以减少为此类小操作启动线程的开销。
标签: java multithreading parallel-processing matrix-multiplication