繁体   English   中英

Java中的多线程矩阵乘法。 平均时间关闭。 我是否正确使用执行程序?

[英]Multi-threaded Matrix Multiplication in Java. Average times are off. Am I using executors correctly?

我正在尝试做多线程矩阵乘法,在其中我比较从1到100的不同数量线程的执行时间,每次迭代增加10。

基本上,我在其单元格中创建两个100x100矩阵,其随机数的范围从-10.0到10.0,然后将它们相乘。 我将使用不同数量的线程(每次再次增加10:这样做25次):因此,第一次迭代将使用1个线程,第二次迭代将使用10个线程,第三次迭代将使用20个线程,等等。)并找到平均值完成时间并将该时间存储在文件中。

我遇到的问题是我不确定我是否正确使用了执行器。 例如,对我来说,这段代码(我也提供了该代码段下方的整个程序代码)是说我已经创建了10个线程,并且在每个线程中,我都将使用.execute方法来运行我的LoopTaskA,是矩阵的乘法。 所以我想做的是将一个乘法分配到这10个线程中。 那是我在这里做什么? 还是我要在10个线程中乘以10倍(即每个线程乘以一)?

我之所以这样问,是因为当我阅读整个程序时,线程计数的每增加一次,我的平均完成时间就会增加。 如果因为要分担工作负载而增加线程数,是否不应该减少完成时间?

根据我在同一网站上发现的另一个问题也许不是吗? 但是我仍然不确定我做错了什么。

for(int i = 0; i < 25; i++)
{
    ExecutorService execService = Executors.newFixedThreadPool(10);
    startTime = System.nanoTime();          
    for(int j = 0; j < 10; j++)
    {
        execService.execute(new LoopTaskA(m1,m2));
    }     

import java.util.*;
import java.io.*;

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

public class MatrixMultiplication { 
    static double[][] m1 = new double[100][100];
    static double[][] m2 = new double[100][100];

public static void main(String[] args){

    long startTime;
    long endTime;
    long completionTime;
    ArrayList<Long> myTimes = new ArrayList<Long>();
    long addingNumber = 0;
    long averageTime;
    String filepath = "exe_time.csv";

    createMatrix();

    /*This for loop will create 1 thread and then use the execute method from execService
    to multiply the two 100x100 matrices together. The completionTime is how long it takes
    for the whole process to finish. We want to run this thread 25 times and then take the average
    of those completion times*/

    for(int i = 0; i < 25; i++)
    {

    ExecutorService execService = Executors.newFixedThreadPool(1);

    startTime = System.nanoTime(); 

    execService.execute(new LoopTaskA(m1,m2));

    execService.shutdown();

    endTime = System.nanoTime();

    completionTime = (endTime - startTime);

    myTimes.add(completionTime);

    System.out.println("The completion time for one iteration is: " + completionTime);

    }

    /*Takes the completion times that were stored in an arraylist and finds the average*/

    for(int i = 0; i < 25; i++)
    {
        addingNumber = addingNumber + myTimes.remove(0);
    }

    averageTime = (addingNumber / 25);
    System.out.println("The average run time in nanoseconds for 1 thread that ran 25 times is: " + averageTime);
    saveRecord(averageTime, filepath);

    /*We call createMatrix again here so we start with a fresh new matrix*/

    createMatrix();

    /*We are doing the same thing as before but now we have 10 threads and not 1*/

    for(int i = 0; i < 25; i++)
    {

    ExecutorService execService = Executors.newFixedThreadPool(10);

    startTime = System.nanoTime();

        for(int j = 0; j < 10; j++)
        {
            execService.execute(new LoopTaskA(m1,m2));
        } 

    execService.shutdown();

    endTime = System.nanoTime();

    completionTime = (endTime - startTime);

    myTimes.add(completionTime);

    System.out.println("The completion time for one iteration is: " + completionTime);

    }

    for(int i = 0; i < 25; i++)
    {
        addingNumber = addingNumber + myTimes.remove(0);
    }

    averageTime = (addingNumber / 25);
    System.out.println("The average run time in nanoseconds for 10 threads that ran 25 times is: " + averageTime);
    saveRecord(averageTime, filepath);

    createMatrix();

    /*We are doing the same thing as before but now we have 20 threads and not 10*/

    for(int i = 0; i < 25; i++)
    {

    ExecutorService execService = Executors.newFixedThreadPool(20);

    startTime = System.nanoTime();

        for(int j = 0; j < 20; j++)
        {
            execService.execute(new LoopTaskA(m1,m2));
        }

    execService.shutdown();

    endTime = System.nanoTime();

    completionTime = (endTime - startTime);

    myTimes.add(completionTime);

    System.out.println("The completion time for one iteration is: " + completionTime);

    }

    for(int i = 0; i < 25; i++)
    {
        addingNumber = addingNumber + myTimes.remove(0);
    }

    averageTime = (addingNumber / 25);
    System.out.println("The average run time in nanoseconds for 20 threads that ran 25 times is: " + averageTime);
    saveRecord(averageTime, filepath);  

 }

/*Creates the matrix input by taking a random number from the range of
    -10 to 10 and then truncates the number to two decimal places*/

public static double matrixInput(){
    double max = 10.0;
    double min = -10.0;

    Random ran = new Random();
    double random = min + (max - min) * ran.nextDouble();
    double truncatedRan = Math.floor(random*100)/100;
    return truncatedRan;

}

/*Places that random number generated in the matrixInput method into a cell of the matrix.
The goal is to create 2 random 100x100 matrices. The first 100x100 matrix is m1. The second is m2.*/

 public static void createMatrix(){

    for (int row = 0; row < m1.length; row++)
    {
        for (int col = 0; col < m1[0].length; col++)
        {
            m1[row][col] = matrixInput();
        }
    }

    for (int row = 0; row < m2.length; row++)
    {
        for (int col = 0; col < m2[0].length; col++)
        {
            m2[row][col] = matrixInput();
        }
    }

}

/*Method that creates a .csv (comma seperated vector) file which stores 
the average time*/

public static void saveRecord(long averageTime, String filepath)
{
    try
    {
        FileWriter fw = new FileWriter(filepath,true);
        BufferedWriter bw = new BufferedWriter(fw);
        PrintWriter pw = new PrintWriter(bw);

        pw.println(averageTime + ",");
        pw.flush();
        pw.close();

        System.out.println("File has been saved.");
    }   
    catch(Exception E)
    {
        System.out.println("File has NOT been saved.");
    }       
  } 
 }

 import java.util.*;
 public class LoopTaskA implements Runnable{

 double[][] m1;
 double[][] m2;

 @Override
 public void run(){     
    double sum = 0;     
    /*This is to calculate the resulting matrix.We need to know the number or rows of m1 
    and the number of columns in m2 (both of which will be 100 since we want a 100x100 matrix)*/

    double r[][] = new double [100][100];

    /*This multiplies the two 100x100 matrices together. You can think of i here as the row number (which is 100).
    The range of j will depend upon the number of columns in the resultant matrix (range of j = 100)
    The k value will depend upon the number of columns in the first matrix or the number of rows in 
    the second matrix, both of these 100*/
    for(int i = 0; i < 100; i++)
    {

        for(int j = 0; j < 100; j++)
        {
            for(int k = 0; k < 100; k++)
            {
                sum = sum + m1[i][k] * m2[k][j];
            }
            r[i][j] = Math.floor(sum*100)/100;
            sum = 0; //reset to 0 so you can do the calculation for the next value.
        }

    }

    /* for(int i = 0; i < 100; i++)
    {
        for(int j = 0; j < 100; j++)
        {
            System.out.print(r[i][j] + " ");
        }

            System.out.println();
    } */        
 }


 public LoopTaskA(double[][] m1, double[][] m2){
    this.m1 = m1;
    this.m2 = m2;
 }  
}

我在您的代码中仅发现一个问题,应该在shutdown之后调用awaitTermination来阻止当前线程。 shutdown不等待先前提交的任务完成执行。


如果因为要分担工作负载而增加线程数,是否不应该减少完成时间?

不,可用硬资源(例如,处理器数量)受到限制。 多线程并不总是带来更高的性能,您可以检查问题。

此外,由Executors.newFixedThreadPool()创建的ThreadPoolExecutor用于解决特定问题:

线程池解决了两个不同的问题:由于减少了每个任务的调用开销,它们通常在执行大量异步任务时提供改进的性能,并且它们提供了一种绑定和管理资源(包括线程)的方法,这些资源在执行一个集合时消耗掉了。任务。


因此,从技术上讲,您使用的是正确的ExecutorSevice 但是并不能保证增加线程数就可以获得更高的性能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM