多线程矩阵乘法性能问题

时间:2018-04-28 23:46:03

标签: java multithreading

我正在使用java进行多线程乘法。我正在练习多线程编程。以下是我从另一篇stackoverflow文章中获取的代码。

public class MatMulConcur {

private final static int NUM_OF_THREAD =1 ;
private static Mat matC;

public static Mat matmul(Mat matA, Mat matB) {
matC = new Mat(matA.getNRows(),matB.getNColumns());
return mul(matA,matB);
}

private static Mat mul(Mat matA,Mat matB) {

int numRowForThread;
int numRowA = matA.getNRows();
int startRow = 0;

Worker[] myWorker = new Worker[NUM_OF_THREAD];

for (int j = 0; j < NUM_OF_THREAD; j++) {
    if (j<NUM_OF_THREAD-1){
        numRowForThread = (numRowA / NUM_OF_THREAD);
    } else {
        numRowForThread = (numRowA / NUM_OF_THREAD) + (numRowA % NUM_OF_THREAD);
    }
    myWorker[j] = new Worker(startRow, startRow+numRowForThread,matA,matB);
    myWorker[j].start();
    startRow += numRowForThread;
}

for (Worker worker : myWorker) {
    try {
        worker.join();
    } catch (InterruptedException e) {

    }
  }
  return matC;
 }

private static class Worker extends Thread {

private int startRow, stopRow;
private Mat matA, matB;

public Worker(int startRow, int stopRow, Mat matA, Mat matB) {
    super();
    this.startRow = startRow;
    this.stopRow = stopRow;
    this.matA = matA;
    this.matB = matB;
}

@Override
public void run() {
    for (int i = startRow; i < stopRow; i++) {
        for (int j = 0; j < matB.getNColumns(); j++) {
            double sum = 0;
            for (int k = 0; k < matA.getNColumns(); k++) {
                sum += matA.get(i, k) * matB.get(k, j);
            }
            matC.set(i, j, sum);
        }
    }
  }
}

我为1,10,20,...,100个线程运行此程序,但性能正在下降。以下是时间表

  1. 线程1需要18毫秒
  2. 线程10需要18毫秒
  3. 线程20需要35毫秒
  4. 线程30需要38毫秒
  5. 线程40需要43毫秒
  6. 线程50需要48毫秒
  7. 线程60需要57毫秒
  8. 线程70需要66毫秒
  9. 线程80需要74毫秒
  10. 线程90需要87毫秒
  11. 线程100需要98毫秒
  12. 任何想法?

2 个答案:

答案 0 :(得分:2)

人们认为使用多个线程会自动(神奇地!)使任何计算更快。这不是 1

有许多因素可以使多线程加速比您预期的低,或者确实导致速度减慢。

  1. 具有N个核心(或超线程)的计算机最多可以计算的计算次数是具有1个核心的计算机的N倍。这意味着当你有T个线程时,T> N,计算性能将限制在N.(除此之外,线程因时间切片而取得进展。)

  2. 计算机具有一定的内存带宽;即,它只能在主存储器上每秒执行一定数量的读/写操作。如果你有一个 demand 超过内存子系统可以实现的应用程序,它将停止(几纳秒)。如果有许多核心同时执行多个线程,那么重要的是总需求。

  3. 处理共享变量或数据结构的典型多线程应用程序将使用volatile或显式同步来执行此操作。这两者都增加了对内存系统的需求。

  4. 当使用显式同步并且两个线程想要同时保持锁定时,其中一个将被阻止。此锁争用会降低计算速度。实际上,如果锁上存在过去争用,计算速度可能会放慢。

  5. 线程创建很昂贵。即使从线程池中获取现有线程也可能相对昂贵。如果您使用该线程执行的任务太小,设置成本可能会超过可能的加速。

  6. 还有一个问题是,您可能会遇到写得不好的基准问题;例如在进行定时测量之前,JVM可能无法正常预热。

    您的问题中没有足够的细节来确定上述哪些因素可能会影响您的应用程序的性能。但它可能是1 2和5的组合...取决于使用了多少内核,CPU内存缓存有多大,矩阵有多大以及其他因素。

    1 - 事实上,如果这是真的,那么我们就不需要购买具有大量核心的计算机。我们可以使用越来越多的线程。如果你有足够的内存,你可以在一台机器上进行无限的计算量。比特币开采将是一个轻而易举的事。当然,不是真的

答案 1 :(得分:0)

使用多线程主要不是为了提高性能,而是为了并行化。但是,有些情况下并行化可以使性能受益。

您的计算机没有无限的资源。添加越来越多的线程会降低性能。就像启动越来越多的应用程序一样,当你启动另一个程序时,你不会期望程序运行得更快,如果它运行得慢,你可能不会感到惊讶。

在某一点上,性能将保持不变(您的计算机仍有资源来处理需求),但在某些时候,您达到计算机可以处理的最大值并且性能将下降。这正是你的结果所显示的。性能在1或10个线程中保持不变,然后稳定下降。