Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程矩阵乘法_Java_Multithreading - Fatal编程技术网

Java 多线程矩阵乘法

Java 多线程矩阵乘法,java,multithreading,Java,Multithreading,我编写了一个多线程矩阵乘法。我相信我的方法是正确的,但我不是100%肯定。关于线程,我不明白为什么我不能只运行(新的MatrixThread(…).start(),而不使用ExecutorService 此外,当我对多线程方法与经典方法进行基准测试时,经典方法要快得多 我做错了什么 矩阵类: import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;

我编写了一个多线程矩阵乘法。我相信我的方法是正确的,但我不是100%肯定。关于线程,我不明白为什么我不能只运行
(新的MatrixThread(…).start()
,而不使用
ExecutorService

此外,当我对多线程方法与经典方法进行基准测试时,经典方法要快得多

我做错了什么

矩阵类:

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Matrix
{
   private int dimension;
   private int[][] template;

   public Matrix(int dimension)
   {
      this.template = new int[dimension][dimension];
      this.dimension = template.length;
   }

   public Matrix(int[][] array) 
   {
      this.dimension = array.length;
      this.template = array;      
   }

   public int getMatrixDimension() { return this.dimension; }

   public int[][] getArray() { return this.template; }

   public void fillMatrix()
   {
      Random randomNumber = new Random();
      for(int i = 0; i < dimension; i++)
      {
         for(int j = 0; j < dimension; j++)
         {
            template[i][j] = randomNumber.nextInt(10) + 1;
         }
      }
   }

   @Override
   public String toString()
   {
      String retString = "";
      for(int i = 0; i < this.getMatrixDimension(); i++)
      {
         for(int j = 0; j < this.getMatrixDimension(); j++)
         {
            retString += " " + this.getArray()[i][j];
         }
         retString += "\n";
      }
      return retString;
   }

   public static Matrix classicalMultiplication(Matrix a, Matrix b)
   {      
      int[][] result = new int[a.dimension][b.dimension];
      for(int i = 0; i < a.dimension; i++)
      {
         for(int j = 0; j < b.dimension; j++)
         {
            for(int k = 0; k < b.dimension; k++)
            {
               result[i][j] += a.template[i][k] * b.template[k][j];
            }
         }
      }
      return new Matrix(result);
   }

   public Matrix multiply(Matrix multiplier) throws InterruptedException
   {
      Matrix result = new Matrix(dimension);
      ExecutorService es = Executors.newFixedThreadPool(dimension*dimension);
      for(int currRow = 0; currRow < multiplier.dimension; currRow++)
      {
         for(int currCol = 0; currCol < multiplier.dimension; currCol++)
         {            
            //(new MatrixThread(this, multiplier, currRow, currCol, result)).start();            
            es.execute(new MatrixThread(this, multiplier, currRow, currCol, result));
         }
      }
      es.shutdown();
      es.awaitTermination(2, TimeUnit.DAYS);
      return result;
   }

   private class MatrixThread extends Thread
   {
      private Matrix a, b, result;
      private int row, col;      

      private MatrixThread(Matrix a, Matrix b, int row, int col, Matrix result)
      {         
         this.a = a;
         this.b = b;
         this.row = row;
         this.col = col;
         this.result = result;
      }

      @Override
      public void run()
      {
         int cellResult = 0;
         for (int i = 0; i < a.getMatrixDimension(); i++)
            cellResult += a.template[row][i] * b.template[i][col];

         result.template[row][col] = cellResult;
      }
   }
} 

另外,如果需要进一步的澄清,请告诉我。

创建线程涉及大量开销,即使在使用ExecutorService时也是如此。我怀疑,多线程方法之所以如此缓慢,是因为您花费99%的时间创建一个新线程,而实际计算只花费1%或更少的时间


通常,要解决这个问题,您需要将一系列操作批处理在一起,并在单个线程上运行这些操作。在这种情况下,我不是百分之百地知道该怎么做,但我建议将矩阵分解成更小的块(比如,10个更小的矩阵),并在线程上运行这些块,而不是在自己的线程中运行每个单元格。

首先,在使用4个四核的四核上,您应该使用一个新的FixedThreadPool,其大小与您拥有的内核相同。其次,不要为每个矩阵创建一个新的矩阵

如果将executorservice设置为静态成员变量,则在矩阵大小为512的情况下,线程化版本的执行速度几乎始终更快


另外,将MatrixThread更改为实现Runnable而不是扩展Thread还可以将执行速度提高到我的机器上线程所在的位置,在512上的速度是创建大量线程的速度的2倍。不仅创建线程的成本很高,而且对于CPU受限的应用程序,您不需要比可用处理器更多的线程(如果需要,您必须花费处理能力在线程之间切换,这也可能导致非常昂贵的缓存未命中)

也不需要将线程发送到
execute
;它只需要一个
可运行的
。通过应用这些更改,您将获得巨大的性能提升:

  • ExecutorService
    设置为静态成员,根据当前处理器调整其大小,并向其发送
    ThreadFactory
    ,使其在
    main
    完成后不会保持程序运行。(在体系结构上,将其作为参数发送到方法,而不是将其作为静态字段保存,可能会更简洁;我将此作为练习留给读者。☺)

  • 使
    MatrixThread
    实现
    Runnable
    而不是继承
    Thread
    。创建线程的成本很高;POJO非常便宜。您还可以将其设置为
    静态
    ,这会使实例更小(因为非静态类获得对封闭对象的隐式引用)

  • 从更改(1)中,您不能再等待终止以确保所有任务都已完成(因为此工作人员池)。相反,请使用
    submit
    方法,该方法返回一个
    Future
    。收集列表中的所有Future对象,提交所有任务后,在列表上迭代,并为每个对象调用
    get

  • 您的
    multiply
    方法现在应该如下所示:

    public Matrix multiply(Matrix multiplier) throws InterruptedException {
        Matrix result = new Matrix(dimension);
        List<Future<?>> futures = new ArrayList<Future<?>>();
        for(int currRow = 0; currRow < multiplier.dimension; currRow++) {
            for(int currCol = 0; currCol < multiplier.dimension; currCol++) {            
                Runnable worker = new MatrixThread(this, multiplier, currRow, currCol, result);
                futures.add(workerPool.submit(worker));
            }
        }
        for (Future<?> f : futures) {
            try {
                f.get();
            } catch (ExecutionException e){
                throw new RuntimeException(e); // shouldn't happen, but might do
            }
        }
        return result;
    }
    

    它仍然不太好,但基本上多线程版本可以计算任何您需要耐心等待的内容,并且它比单线程版本更快。

    您的代码缺少“乘法”方法为什么要使用这样的多线程?这是完全受CPU限制的,不像有线程被阻塞等待I/O。多线程可以正常工作,但更多地取决于有多少CPU(在您的示例中,10x10乘以10x10创建100个线程…您可能只有2-8个CPU)以及矩阵有多大(它们是否适合二级/三级缓存?)。像MKL和OpenCL这样的本机库在这方面做得更好。matt b:多个硬件线程??尽管可能远不及其中的n^2个。关于扩展
    线程
    。几乎总是一个坏主意。在这种情况下,代码甚至不会启动线程。
    线程
    实现
    可运行
    的事实是不幸的。谢谢你非常感谢您的帮助!代码有点混乱,但我想我能弄明白。出于某种原因,当我运行代码时,非线程版本速度更快,但它与以前相比有了更合理的差异。谢谢!嗯,将作业分成几个部分总是会有开销。对于 n
    多线程版本可能总是比较慢,但是
    n
    越大,多线程版本可能越好。此解决方案在创建
    n
    任务时仍有相当大的开销(因此同步开销为
    O(n)
    )。如果您可以让它将乘法分解为最多一些固定数量的任务(例如,
    可用处理器*2
    或其他),那么对于
    n
    的大值,程序会更快。此外,对于
    n
    的小值,您可以只执行非线程乘法,因为它可能总是更快。
    private static final ExecutorService workerPool = 
        Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setDaemon(true); 
                return t;
            }
        });
    
    private static class MatrixThread implements Runnable
    
    public Matrix multiply(Matrix multiplier) throws InterruptedException {
        Matrix result = new Matrix(dimension);
        List<Future<?>> futures = new ArrayList<Future<?>>();
        for(int currRow = 0; currRow < multiplier.dimension; currRow++) {
            for(int currCol = 0; currCol < multiplier.dimension; currCol++) {            
                Runnable worker = new MatrixThread(this, multiplier, currRow, currCol, result);
                futures.add(workerPool.submit(worker));
            }
        }
        for (Future<?> f : futures) {
            try {
                f.get();
            } catch (ExecutionException e){
                throw new RuntimeException(e); // shouldn't happen, but might do
            }
        }
        return result;
    }
    
     public Matrix multiply(Matrix multiplier) throws InterruptedException {
         Matrix result = new Matrix(dimension);
         List<Future<?>> futures = new ArrayList<Future<?>>();
         for(int currRow = 0; currRow < multiplier.dimension; currRow++) {
             Runnable worker = new MatrixThread2(this, multiplier, currRow, result);
             futures.add(workerPool.submit(worker)); 
         }
         for (Future<?> f : futures) {
             try {
                 f.get();
             } catch (ExecutionException e){
                 throw new RuntimeException(e); // shouldn't happen, but might do
             }
         }
         return result;
     }
    
    
    private static class MatrixThread2 implements Runnable
    {
       private Matrix self, mul, result;
       private int row, col;      
    
       private MatrixThread2(Matrix a, Matrix b, int row, Matrix result)
       {         
          this.self = a;
          this.mul = b;
          this.row = row;
          this.result = result;
       }
    
       @Override
       public void run()
       {
          for(int col = 0; col < mul.dimension; col++) {
             int cellResult = 0;
             for (int i = 0; i < self.getMatrixDimension(); i++)
                cellResult += self.template[row][i] * mul.template[i][col];
             result.template[row][col] = cellResult;
          }
       }
    }