简体   繁体   English

如何在Java中使用多线程实现2D方阵乘法?

[英]How can I implement 2D Square Matrix multiplication using multi-threading in Java?

I want to multiply two square 2D matrix using multi-threading features in Java in order to save time. 我想使用Java中的多线程功能将两个正方形2D矩阵相乘,以节省时间。

What is the best way to do this? 做这个的最好方式是什么? My first priority is to save time. 我的首要任务是节省时间。

Please look at the code that I wrote. 请查看我编写的代码。 The solution I am looking is that it will do what my code do but only difference is execution time. 我正在寻找的解决方案是它将执行我的代码所执行的操作,但唯一的区别是执行时间。

Multi-Threading should save time right? 多线程应该节省时间对吗?

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

public class ExtraTaskOS {

    // Generatining Random Number Method
    static int generateRandomNumber() {

        int number = (int) (Math.random() * (9 - 1)) + 1;
        return number;
    }

    public static void main(String[] args) throws IOException {

        // Store current time
        long startTime = System.nanoTime();

        Scanner sc = new Scanner(System.in);

        System.out.print("Enter number of Eelement for both Square Matrix: ");
        int n = sc.nextInt();


        // Generaing First Matrix
        int[][] matrix01 = new int[n][n];

        for (int i = 0; i < matrix01.length; i++) {
            for (int j = 0; j < matrix01.length; j++) {
                matrix01[i][j] = generateRandomNumber();
            }
        }

        // Writing Matrix01 to Text File
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < matrix01.length; i++)//for each row
        {
            for (int j = 0; j < matrix01.length; j++)//for each column
            {
                builder.append(matrix01[i][j] + "");//append to the output string
                if (j < matrix01.length - 1)//if this is not the last row element
                {
                    builder.append(",");//then add comma (if you don't like commas you can use spaces)
                }
            }
            builder.append("\n");//append new line at the end of the row
        }
        BufferedWriter writer = new BufferedWriter(new FileWriter("matrix01.txt"));
        writer.write(builder.toString());//save the string representation of the board
        writer.close();

        // Generating Second Matix
        int[][] matrix02 = new int[n][n];

        for (int i = 0; i < matrix02.length; i++) {
            for (int j = 0; j < matrix02.length; j++) {
                matrix02[i][j] = generateRandomNumber();
            }
        }

        // Writing Matrix02 to Text File
        StringBuilder builder2 = new StringBuilder();

        for (int i = 0; i < matrix02.length; i++)//for each row
        {
            for (int j = 0; j < matrix02.length; j++)//for each column
            {
                builder2.append(matrix02[i][j] + "");//append to the output string
                if (j < matrix02.length - 1)//if this is not the last row element
                {
                    builder2.append(",");//then add comma (if you don't like commas you can use spaces)
                }
            }
            builder2.append("\n");//append new line at the end of the row
        }
        BufferedWriter writer2 = new BufferedWriter(new FileWriter("matrix02.txt"));
        writer2.write(builder2.toString());//save the string representation of the board
        writer2.close();

        // Printing both 2D Arrays
        for (int[] arr : matrix01) {
            System.out.println(Arrays.toString(arr));
        }
        System.out.println("");
        for (int[] arr : matrix02) {
            System.out.println(Arrays.toString(arr));
        }

        // Multiplying both matrix
        int[][] productTwoMatrix = new int[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {

              for(int k=0; k<n; k++){
                productTwoMatrix[i][j] += matrix01[i][k] * matrix02[k][j];

              }  

            }
        }

        // Printing Result
        System.out.println("\nResult: ");
        for (int[] arr : productTwoMatrix) {
            System.out.println(Arrays.toString(arr));
        }

        // Calculate Execution time
        long endTime = System.nanoTime();
        long totalTime = endTime - startTime;
        long timeInMiliSecond = (totalTime / 1_000_000);
        System.out.println("Execution Time: "+ timeInMiliSecond + " miliseconds");


    }

}

The new code using multi-threading should save time. 使用多线程的新代码应节省时间。

First: learn how to properly measure your code. 首先:学习如何正确评估代码。 You do 你做

// Store current time
long startTime = System.nanoTime();

even before you ask the user for his input. 甚至您要求用户输入之前。 Then you do file IO and print various things to System.out. 然后,您进行文件IO并将各种内容打印到System.out。 Hint: each of those actions will probably take hundreds of milliseconds, waiting for a human to enter a number ... could take hours. 提示:这些动作中的每一个动作可能要花费数百毫秒,等待人类输入数字……可能要花费数小时。 Thus: only measure the part that really matters to you (that would be the multiplication part). 因此: 测量对您真正重要的部分(即乘法部分)。 Avoid all kinds of IO operation while measuring, too! 测量时也要避免各种IO操作!

You see, hundred milliseconds, that doesn't sound much, but when you do correct measurements, you will find that your CPU can do a ton of things in 100 ms (if you don't disturb it all the time with IO work). 您会看到几百毫秒,这听起来并不多,但是当您进行正确的测量时,您会发现您的CPU可以在100毫秒内完成很多工作(如果您不会一直在进行IO工作时打扰它) 。

Regarding multiple threads, you are also going down the wrong rabbit hole: 关于多线程,您还会遇到错误的兔子漏洞:

I want to multiply two square 2D matrix using multi-threading features in Java in order to save time. 我想使用Java中的多线程功能将两个正方形2D矩阵相乘,以节省时间。

That is (almost) non-sensical. 那(几乎)是荒谬的。 You see, CPU intensive workloads do not profit from using multiple threads. 您会看到,占用大量CPU的工作负载无法从使用多个线程中获利。 In the end, the CPU needs to turn to memory, fetch values, do a few computations, and write back values to memory. 最后,CPU需要转向内存,获取值,进行一些计算,然后将值写回内存。 Doing that in parallel isn't necessarily making things go faster. 并行执行此操作不一定会使处理速度更快。 To the contrary, you first have to "pay" various penalty fees: 相反,您首先必须“支付”各种罚款:

  • Creating a thread isn't a cheap operation. 创建线程不是一个便宜的操作。 You must for sure process thousands of elements before alone the price tag for new Thread() has been made up for. 在确定new Thread()的价格标签之前,您必须确保处理成千上万个元素。
  • When we talk huge arrays (and as said: small arrays will definitely give you worse results when using more than one thread) ... then it matters quite a bit in which order data is requested from memory. 当我们讨论大型数组时(如前所述:使用多个线程时,小型数组肯定会给您带来更糟糕的结果)...那么从内存中请求顺序数据就相当重要了。 You know, CPUs have caches. 您知道,CPU有缓存。 A cache miss can be extremely expensive. 高速缓存未命中可能非常昂贵。 And guess what happens when you have multiple threads accessing different parts of your matrixes? 猜猜当您有多个线程访问矩阵的不同部分时会发生什么? Exactly: you will most likely cause that: cache misses. 确实:您很可能会导致以下原因:缓存未命中。

In case I didn't discourage you, and you actually do this for learning purposes, the answer is quite simple. 万一我不劝阻您,而您实际上是出于学习目的而这样做,答案很简单。 Matrix multiplication works by fetching the values of one row, and the values from a column of the other matrix, you multiple and sum up the results. 矩阵乘法的工作原理是:获取一行的值,并从另一矩阵的一列中获取值,然后对它们进行乘法运算并求和。

Now: instead of having one thread going in three loops to do these things, you could for example have one thread compute the first row of the result matrix, the second thread computes the second row, and so on. 现在:您可以让一个线程计算结果矩阵的第一行,而第二个线程计算第二行,以此类推,而不是让一个线程进入三个循环来执行这些操作。

The nice thing here: you can simply "slice" the data that needs to be processed. 这里的好处是:您可以简单地“切片”需要处理的数据。 No result value depends on other results, so there is no need for synchronisation at all. 没有结果值取决于其他结果,因此完全不需要同步。 You can use 1 thread, 2, 4, n, almost as many you want to. 您可以使用1个线程,2、4,n,几乎可以使用任意数量的线程。

What I would suggest: 我的建议是:

  • don't ask the user for any input. 不要要求用户输入任何内容。 Simply generate matrixes of a fixed size, maybe 100x100, 1000x1000, 10000x10000. 只需生成固定大小(例如100x100、1000x1000、10000x10000)的矩阵即可。
  • maybe seed your random number generator, so that all multiplications operate on the exact same data. 可能会为您的随机数生成器播种,以便所有乘法都对完全相同的数据进行运算。 - don't print the whole array in the end (because as said: use large arrays). -不要最后打印整个数组(因为如前所述:使用大数组)。 An array that fits on your screen is too small to give you any meaningful measurements. 屏幕上适合的阵列太小,无法进行有意义的测量。 But sum up the final matrix for example (to avoid that the JIT optimizes away the whole operation: you have to make sure that some result of your operation is used somehow) 但是,例如, 总结一下最终矩阵(为避免JIT优化整个操作:您必须确保以某种方式使用了某些操作结果)
  • try to write code that allows you to quickly change the number of threads, without changing anything else. 尝试编写允许您快速更改线程数而不更改任何其他内容的代码。 So that you can multiple using 1, 2, 4, 8, 16 threads. 这样就可以使用1、2、4、8、16个线程进行多重处理。

And when you are done with using raw, "bare metal" threads, copy your code, remove all the thread stuff, and try implementing matrix multiplication using an ExecutorService . 使用完原始的“裸机”线程后,复制代码,删除所有线程内容,然后尝试使用ExecutorService实现矩阵乘法。 When that works, go one step further and look at Futures and think how those could be used here. 当这种方法可行时,请进一步研究一下期货,并思考如何在这里使用这些期货

As said: you shouldn't be doing this for performance. 如前所述:您不应该这样做来提高性能。 The only good reason for you to write such code is to learn how to do it (right). 您编写此类代码的唯一好理由是学习如何做(正确)。

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

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