我最近开始在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秒.这听起来很现实,因为它超过单线程方法的一半.但为什么它比第一个版本慢得多?我会假设两次转置矩阵比获取矩阵元素的额外时间慢?有没有我缺少的东西或使用矩阵真的比使用矢量慢得多?
我希望有人能回答这些问题.很抱歉写这么长的帖子.
此致
托尔斯滕
您应该尝试的第一个实验是:使用矩阵转置和向量乘法编写单线程版本.你会发现它的速度要快得多 – 可能与转置的多线程版本一样快.
原始单线程版本之所以如此之慢,是因为它必须为列中的每个单元格加载一个缓存块.如果使用矩阵转置,则所有这些单元格在内存中是顺序的,加载一个块会获得一堆它们.
因此,如果您想优化矩阵乘法,FIRST优化内存访问以提高缓存效率,那么就可以在几个线程之间划分工作 – 不超过核心数量的两倍.更多的东西只是浪费时间和资源与上下文切换等.
关于你的其他问题:
1)使用lambdas可以方便地从创建它们的范围中捕获变量,例如:
for(int i=0; i
2)GC将负责处理.您不需要显式关闭线程池以释放任何资源.