java – 多线程矩阵乘法

前端之家收集整理的这篇文章主要介绍了java – 多线程矩阵乘法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我最近开始在java中学习多线程.由于我正在为我的大学编写一个数值计算程序,我决定通过编程多线程矩阵乘法进行一些初步尝试.

这是我的代码.请记住,这只是作为第一次尝试,并不是很干净.

    public class MultithreadingTest{

        public static void main(String[] args) {
            // TODO Auto-generated method stub
            double[][] matrix1 = randomSquareMatrix(2000);
            double[][] matrix2 = randomSquareMatrix(2000);

            matrixMultiplication(matrix1,matrix2,true);
            matrixMultiplicationSingleThread(matrix1,matrix2);
            try {
                matrixMultiplicationParallel(matrix1,true);
            } catch (InterruptedException | ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                matrixMultiplicationParallel2(matrix1,true);
            } catch (InterruptedException | ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

        public static double[][] randomSquareMatrix(int n){
            double[][] mat = new double[n][n];
            Random rand = new Random();
            for(int i=0; i

我有两个关于多线程的一般性问题,我希望没有为此开设一个新主题.

>有没有办法编写代码而不需要为实现runnable或callable的线程添加其他类?我查看了使用匿名内部类和lambdas的方法,但据我有fount信息,我不能以这种方式将参数传递给线程,因为run()和call()不接受任何,即除非参数是最后的.但是假设我为矩阵运算编写了一个类,我宁愿不为每个想在线程中运行的操作编写一个additinal类.
>假设我的类做了很多多线程操作,创建一个新的线程池并在每个方法关闭它会浪费大量资源,我想.所以我想创建一个线程池作为我的类的成员,在需要时使用invokeAll实例化它.但如果我的对象被删除会发生什么?我是否会因为我从未关闭线程池而遇到问题?在C中,我会使用析构函数.或者gc在这种情况下是否会处理所有事情?

现在直接告诉我的代码

我以四种不同的方式实现矩阵乘法,作为在我的主线程中运行的方法,作为在新线程中运行的方法,但仍然没有多线程(以确保我的主线程中不会有任何后台操作减慢它),以及两个多线程矩阵乘法的不同方法.第一个版本转换第二个矩阵,将乘法作为向量 – 向量乘法提交,并将矩阵转换回其原始形式.第二个版本直接采用矩阵,并且另外采用两个索引来定义矢量矢量乘法的矩阵的行和列.

对于所有版本,我测量了乘法所需的时间,并计算了得到的矩阵的平均值,以查看结果是否相同.

我在两台计算机上运行此代码,包括相同的JVM和Windows 10.第一台是我的笔记本电脑,i5第5代,2,6 Ghz双核,第二台是我的台式电脑,i5第4代,4,2 Ghz四核.

我希望我的台式电脑更快.我还期望多线程版本占用了单元线程版本的大约一半/四分之一的时间,但更多的是因为还有额外的工作来创建线程等.最后,我期望第二个多线程版本,它不转置一个矩阵两倍,更快,因为操作较少.

运行代码后,我对结果有点困惑,希望有人能向我解释一下:

对于两种单线程方法,我的笔记本电脑需要大约340s(矩阵大小为3000).所以我假设在我的主线程中没有完成昂贵的后台任务.另一方面,我的桌面PC需要440s.现在的问题是,为什么我的笔记本电脑速度更快,速度更快?即使第五代比第四代更快,因为我的台式电脑以我的笔记本电脑的速度运行1.6倍,我仍然期望它更快.这些世代之间的差异不太大.

对于多线程方法,我的笔记本电脑需要大约34秒.如果多线程是完美的,那么它不应该少于一半.为什么它在两个线程上快十倍?我的台式电脑也是如此.使用四个线程,乘法在16s而不是440s完成.这就像我的桌面PC工作速度与我的笔记本电脑相同,只有四个而不是两个线程.

现在,对于两个多线程方法之间的比较,两次转换一个矩阵的版本在我的笔记本电脑上花费大约34秒,直接占用矩阵的版本大约需要200秒.这听起来很现实,因为它超过单线程方法的一半.但为什么它比第一个版本慢得多?我会假设两次转置矩阵比获取矩阵元素的额外时间慢?有没有我缺少的东西或使用矩阵真的比使用矢量慢得多?

我希望有人能回答这些问题.很抱歉写这么长的帖子.

此致
托尔斯滕

最佳答案
这个问题的答案很明显:矩阵乘法所需的时间主要是将数据从RAM移动到cpu缓存所花费的时间.您可能有4个内核,但只有1个RAM总线,因此如果它们都相互阻塞等待内存访问,则使用更多内核(多线程)将无法获得任何好处.

您应该尝试的第一个实验是:使用矩阵转置和向量乘法编写单线程版本.你会发现它的速度要快得多 – 可能与转置的多线程版本一样快.

原始单线程版本之所以如此之慢,是因为它必须为列中的每个单元格加载一个缓存块.如果使用矩阵转置,则所有这些单元格在内存中是顺序的,加载一个块会获得一堆它们.

因此,如果您想优化矩阵乘法,FIRST优化内存访问以提高缓存效率,那么就可以在几个线程之间划分工作 – 不超过核心数量的两倍.更多的东西只是浪费时间和资源与上下文切换等.

关于你的其他问题:

1)使用lambdas可以方便地从创建它们的范围中捕获变量,例如:

for(int i=0; i

2)GC将负责处理.您不需要显式关闭线程池以释放任何资源.

猜你在找的Java相关文章