Java 可以使用多线程来提高矩阵向量乘法算法的效率吗?

Java 可以使用多线程来提高矩阵向量乘法算法的效率吗?,java,multithreading,Java,Multithreading,对于我正在编写的程序,我想实现我自己的矩阵向量乘法算法。这是它的代码 static <T extends List<Double>> List<Double> matrixVectorMulti(List<T> matrix, List<Double> vector) { List<Double> output = new ArrayList<>(); for(int row = 0; row

对于我正在编写的程序,我想实现我自己的矩阵向量乘法算法。这是它的代码

static <T extends List<Double>> List<Double> matrixVectorMulti(List<T> matrix, List<Double> vector) {
    List<Double> output = new ArrayList<>();

    for(int row = 0; row < matrix.size(); row++) {
        double sum = 0;
        for (int column = 0; column < vector.size(); column++) {
            sum += matrix.get(row).get(column) * vector.get(column);
        }

        output.add(sum);
    }

    return output;
}
静态列表矩阵xvectomulti(列表矩阵,列表向量){
列表输出=新的ArrayList();
对于(int row=0;row
是否可以使用多线程来提高算法的性能,或者我的算法是否更有效。另外,如果您能为我提供一个多线程实现的示例代码,那将非常有帮助


注意:列表列表用于对矩阵建模,列表用于对向量建模

使用多线程来提高算法的效率涉及到将问题分解成更小的单元,这些单元可以并行运行,并聚合每个单元的结果

要分解您的算法,您可以使用分而治之的策略,如中所述
并在其自己的线程中运行每个子任务。然而,同步的开销使得它几乎不值得实现。

使用多线程使算法高效涉及到将问题分解为可并行运行的较小单元,并聚合每个单元的结果

要分解您的算法,您可以使用分而治之的策略,如中所述
并在其自己的线程中运行每个子任务。然而,同步的开销使得它很难实现。

多线程是否能提高性能实际上取决于许多因素

  • 矩阵中有多少数据
  • (虚拟)计算机有多少个进程
  • 工作负载的类型(CPU密集型、IO限制型)
  • 许多其他因素
您拥有的用例是CPU密集型(与最少IO相乘)。假设
matrix
非常庞大,那么通过实现多线程,您可能会获得一定程度的好处

下面是多线程的一个版本,它利用了并行处理(线程的数量几乎等于可用于处理的处理器的数量)

请记住,还有其他方法可以提高性能。。。如初始化
输出
带有矩阵大小的ArrayList等

注意:下面计算的性能统计数据不是一种科学的方法。。。这只是一种非正式的计算方法。代码没有经过充分测试。但它可以给你一个想法

package my.package;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class MatrixMultiplication {

    public List<Double> matrixVectorMulti(List<List<Double>> matrix, List<Double> vector) {
        List<Double> output = new ArrayList<>();

        for(int row = 0; row < matrix.size(); row++) {
            double sum = 0;
            for (int column = 0; column < vector.size(); column++) {
                sum += matrix.get(row).get(column) * vector.get(column);
            }
            output.add(sum);
        }
        return output;
    }

    static List<List<Double>> initializeMatrix(int matrix_size) {
        List<List<Double>> matrix = new ArrayList<>();
        int rangeMin = 100;
        int rangeMax = 200;

        for (int i=0; i<matrix_size; i++) {
            List<Double> row = new ArrayList<>();
            for (int j=0; j<matrix_size; j++) {
                row.add(rangeMin + (rangeMax-rangeMin) * new Random().nextDouble());
            }
            matrix.add(row);
        }

        return matrix;
    }

    static List<Double> initializeVector(int matrix_size) {
        List<Double> vector = new ArrayList<>();
        int rangeMin = 100;
        int rangeMax = 200;

        for (int j=0; j<matrix_size; j++) {
            vector.add(rangeMin + (rangeMax-rangeMin) * new Random().nextDouble());
        }
        return vector;
    }

    public List<Double> matrixVectorMultiParallel(List<List<Double>> matrix, List<Double> vector) {
        int numOfThreads = Runtime.getRuntime().availableProcessors();
        List<Double> result = new ArrayList<>();

        //System.out.println(numOfThreads);
        //System.exit(0);
        int batchSize = matrix.size()/numOfThreads;
        PartialVectorMulti[] partialVectorMultis = new PartialVectorMulti[numOfThreads];

        int rangeStart = 0;
        int rangeEnd = 0;
        for (int i=0; i<numOfThreads; i++) {
            rangeEnd = rangeStart + batchSize-1;

            if (i == numOfThreads-1) {
                partialVectorMultis[i] = new PartialVectorMulti(matrix, rangeStart, matrix.size()-1, vector);
            } else {
                partialVectorMultis[i] = new PartialVectorMulti(matrix, rangeStart, rangeEnd, vector);
            }

            partialVectorMultis[i].start();
            rangeStart = rangeEnd + 1;
        }

        for (int i=0; i<numOfThreads; i++) {
            try {
                partialVectorMultis[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (int i=0; i<numOfThreads; i++) {
            result.addAll(partialVectorMultis[i].getPartialResult());
        }

        return result;
    }

    public static void main(String[] args) {
        int matrix_size = 10_000;

        List<List<Double>> matrix = initializeMatrix(matrix_size);
        List<Double> vector = initializeVector(matrix_size);
        List<Double> result;
        List<Double> resultMulti;

        MatrixMultiplication matrixMultiplication = new MatrixMultiplication();

        long startTime = System.currentTimeMillis();
        result = matrixMultiplication.matrixVectorMulti(matrix, vector);
        long endTime = System.currentTimeMillis();
        System.out.println("matrixVectorMulti: " + (endTime-startTime) + "milli seconds");

        startTime = System.currentTimeMillis();
        resultMulti = matrixMultiplication.matrixVectorMultiParallel(matrix, vector);
        endTime = System.currentTimeMillis();
        System.out.println("matrixVectorMultiParallel: " + (endTime-startTime) + "milli seconds");

    }

    class PartialVectorMulti extends Thread {
        List<List<Double>> matrix;
        List<Double> vector;
        int rowStart;
        int rowEnd;
        List<Double> partialResult = new ArrayList<>();

        public PartialVectorMulti(List<List<Double>> matrix, int rowStart, int rowEnd, List<Double> vector) {
            this.matrix = matrix;
            this.rowStart = rowStart;
            this.rowEnd = rowEnd;
            this.vector = vector;
        }

        public List<Double> getPartialResult() {
            return this.partialResult;
        }

        @Override
        public void run() {
            for (int i=rowStart; i<=rowEnd; i++) {
                double sum = 0;
                for (int j=0; j<vector.size(); j++) {
                    sum += matrix.get(i).get(j) * vector.get(j);
                }
                partialResult.add(sum);
            }
        }
    }
}

package my.package;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.Random;
公共类矩阵乘法{
公共列表矩阵VectorMulti(列表矩阵,列表向量){
列表输出=新的ArrayList();
对于(int row=0;row对于(int i=0;i,多线程是否会提高性能实际上取决于许多因素

  • 矩阵中有多少数据
  • (虚拟)计算机有多少个进程
  • 工作负载的类型(CPU密集型、IO限制型)
  • 许多其他因素
您的用例是CPU密集型的(与最少IO相乘)。假设
matrix
非常庞大,您可以通过实现多线程获得一定程度的好处

下面是多线程的一个版本,它利用了并行处理(线程的数量几乎等于可用于处理的处理器的数量)

请记住,还有其他提高性能的方法…如使用矩阵大小初始化
输出
数组列表等

注意:下面计算的性能统计数据不是一种科学的方法…它只是一种非正式的计算方法。代码没有经过充分测试。但是它可以给你一个想法

package my.package;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class MatrixMultiplication {

    public List<Double> matrixVectorMulti(List<List<Double>> matrix, List<Double> vector) {
        List<Double> output = new ArrayList<>();

        for(int row = 0; row < matrix.size(); row++) {
            double sum = 0;
            for (int column = 0; column < vector.size(); column++) {
                sum += matrix.get(row).get(column) * vector.get(column);
            }
            output.add(sum);
        }
        return output;
    }

    static List<List<Double>> initializeMatrix(int matrix_size) {
        List<List<Double>> matrix = new ArrayList<>();
        int rangeMin = 100;
        int rangeMax = 200;

        for (int i=0; i<matrix_size; i++) {
            List<Double> row = new ArrayList<>();
            for (int j=0; j<matrix_size; j++) {
                row.add(rangeMin + (rangeMax-rangeMin) * new Random().nextDouble());
            }
            matrix.add(row);
        }

        return matrix;
    }

    static List<Double> initializeVector(int matrix_size) {
        List<Double> vector = new ArrayList<>();
        int rangeMin = 100;
        int rangeMax = 200;

        for (int j=0; j<matrix_size; j++) {
            vector.add(rangeMin + (rangeMax-rangeMin) * new Random().nextDouble());
        }
        return vector;
    }

    public List<Double> matrixVectorMultiParallel(List<List<Double>> matrix, List<Double> vector) {
        int numOfThreads = Runtime.getRuntime().availableProcessors();
        List<Double> result = new ArrayList<>();

        //System.out.println(numOfThreads);
        //System.exit(0);
        int batchSize = matrix.size()/numOfThreads;
        PartialVectorMulti[] partialVectorMultis = new PartialVectorMulti[numOfThreads];

        int rangeStart = 0;
        int rangeEnd = 0;
        for (int i=0; i<numOfThreads; i++) {
            rangeEnd = rangeStart + batchSize-1;

            if (i == numOfThreads-1) {
                partialVectorMultis[i] = new PartialVectorMulti(matrix, rangeStart, matrix.size()-1, vector);
            } else {
                partialVectorMultis[i] = new PartialVectorMulti(matrix, rangeStart, rangeEnd, vector);
            }

            partialVectorMultis[i].start();
            rangeStart = rangeEnd + 1;
        }

        for (int i=0; i<numOfThreads; i++) {
            try {
                partialVectorMultis[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (int i=0; i<numOfThreads; i++) {
            result.addAll(partialVectorMultis[i].getPartialResult());
        }

        return result;
    }

    public static void main(String[] args) {
        int matrix_size = 10_000;

        List<List<Double>> matrix = initializeMatrix(matrix_size);
        List<Double> vector = initializeVector(matrix_size);
        List<Double> result;
        List<Double> resultMulti;

        MatrixMultiplication matrixMultiplication = new MatrixMultiplication();

        long startTime = System.currentTimeMillis();
        result = matrixMultiplication.matrixVectorMulti(matrix, vector);
        long endTime = System.currentTimeMillis();
        System.out.println("matrixVectorMulti: " + (endTime-startTime) + "milli seconds");

        startTime = System.currentTimeMillis();
        resultMulti = matrixMultiplication.matrixVectorMultiParallel(matrix, vector);
        endTime = System.currentTimeMillis();
        System.out.println("matrixVectorMultiParallel: " + (endTime-startTime) + "milli seconds");

    }

    class PartialVectorMulti extends Thread {
        List<List<Double>> matrix;
        List<Double> vector;
        int rowStart;
        int rowEnd;
        List<Double> partialResult = new ArrayList<>();

        public PartialVectorMulti(List<List<Double>> matrix, int rowStart, int rowEnd, List<Double> vector) {
            this.matrix = matrix;
            this.rowStart = rowStart;
            this.rowEnd = rowEnd;
            this.vector = vector;
        }

        public List<Double> getPartialResult() {
            return this.partialResult;
        }

        @Override
        public void run() {
            for (int i=rowStart; i<=rowEnd; i++) {
                double sum = 0;
                for (int j=0; j<vector.size(); j++) {
                    sum += matrix.get(i).get(j) * vector.get(j);
                }
                partialResult.add(sum);
            }
        }
    }
}

package my.package;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.Random;
公共类矩阵乘法{
公共列表矩阵VectorMulti(列表矩阵,列表向量){
列表输出=新的ArrayList();
对于(int row=0;row对于(int i=0;i是否有示例输入/输出数据?由于这是CPU密集型活动,您可以实现并行执行逻辑。假设您有两个CPU内核(
Runtime.getRuntime().availableProcessors()
),您可以有两个线程执行计算…一个线程用于行=0到矩阵。大小()/2和另一个用于剩余行。您可能需要有多个
输出
并合并结果。要使您的代码与多个线程一起运行,您需要找到一种方法来安全地划分问题。查看您的代码,看起来内部
for
循环中的工作可以发送到单独的线程。例如,如果您有10行,那么您将有10个线程,每个线程为每行数据计算一个单独的
sum