Как правильно умножить матрицу на другую матрицу в нескольких потоках? Моя задача такая. Мне нужно параллельно на 8 потоках умножить матрицу 200x248 на матрицу 248x333. В интернете я нашел простой пример умножения двух матриц 4x4 на 4 потоках, но я не совсем понимаю логику разделения этой задачи между потоками. Почему у каждого потока разные границы циклов и как они вообще образовываются? Почему в каждом потоке аж 3 цикла, а не 2? Можете мне объяснить алгоритм, чтобы я мог по его аналогии сделать умножение огромных матриц на 8 потоках? Вот часть этого кода (там еще есть ввод данных с файла и вывод результата в другой файл, графический интерфейс и другое, но это не столь важно в этом вопросе). Инициализация статических полей:public static int[][] a; public static int[][] b; public static int[][] c; Где-то в main создаются и запускаются потоки:c = new int[a.length][b[0].length]; Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); Thread3 thread3 = new Thread3(); Thread4 thread4 = new Thread4(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } try { thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } try { thread3.join(); } catch (InterruptedException e) { e.printStackTrace(); } try { thread4.join(); } catch (InterruptedException e) { e.printStackTrace(); } Код четырех потоков:public static class Thread1 extends Thread { @Override public void run() { int m = a.length; int n = b[0].length; int k = (a.length) / 4; for (int i = 0; i <= k; i++) { for (int j = 0; j < n; j++) { for (int l = 0; l < b.length; l++) { c[i][j] = c[i][j] + a[i][l] * b[l][j]; } } } } } public static class Thread2 extends Thread { @Override public void run() { int m = a.length; int n = b[0].length; int k = (a.length) / 2 + 1; int s = ((a.length) / 4) + 1; for (int i = s; i < k; i++) { for (int j = 0; j < n; j++) { for (int l = 0; l < b.length; l++) { c[i][j] = c[i][j] + a[i][l] * b[l][j]; } } } } } public static class Thread3 extends Thread { @Override public void run() { int m = a.length; int n = b[0].length; int k = ((3 * (a.length)) / 4) + 1; int s = (a.length) / 2 + 1; for (int i = s; i < k; i++) { for (int j = 0; j < n; j++) { for (int l = 0; l < b.length; l++) { c[i][j] = c[i][j] + a[i][l] * b[l][j]; } } } } } public static class Thread4 extends Thread { @Override public void run() { int m = a.length; int n = b[0].length; int k = ((3 * (a.length)) / 4) + 1; for (int i = k; i < m; i++) { for (int j = 0; j < n; j++) { for (int l = 0; l < b.length; l++) { c[i][j] = c[i][j] + a[i][l] * b[l][j]; } } } } }
Алгоритм разделения задачи умножения матриц на несколько потоков следующий:
Делим результат на число потоков. В вашем случае вы хотите использовать 8 потоков, поэтому делим количество строк матрицы A на 8, чтобы получить границы обработки для каждого потока.
Создаем класс потока, где каждый поток будет обрабатывать свой участок результатной матрицы. В вашем случае это заполнение столбцов результирующей матрицы.
В цикле каждый поток пробегается по своей части результатной матрицы, умножая соответствующие элементы соответствующих строк матриц A и B и записывая результат в соответствующий элемент матрицы C.
После завершения всех потоков, собираем результаты в общей результирующей матрице.
Осуществляем синхронизацию потоков, чтобы дождаться их завершения перед объединением результатов в общую матрицу.
Что касается вашего кода, границы циклов в каждом потоке правильно определены для разделения обработки между потоками. Количество циклов зависит от того, как вы разбили обработку. В вашем случае, чтобы умножить матрицу 200x248 на матрицу 248x333 на 8 потоках, вам нужно дополнительно разделить один из измерений на 8, чтобы обеспечить параллелизм.
Алгоритм разделения задачи умножения матриц на несколько потоков следующий:
Делим результат на число потоков. В вашем случае вы хотите использовать 8 потоков, поэтому делим количество строк матрицы A на 8, чтобы получить границы обработки для каждого потока.
Создаем класс потока, где каждый поток будет обрабатывать свой участок результатной матрицы. В вашем случае это заполнение столбцов результирующей матрицы.
В цикле каждый поток пробегается по своей части результатной матрицы, умножая соответствующие элементы соответствующих строк матриц A и B и записывая результат в соответствующий элемент матрицы C.
После завершения всех потоков, собираем результаты в общей результирующей матрице.
Осуществляем синхронизацию потоков, чтобы дождаться их завершения перед объединением результатов в общую матрицу.
Что касается вашего кода, границы циклов в каждом потоке правильно определены для разделения обработки между потоками. Количество циклов зависит от того, как вы разбили обработку. В вашем случае, чтобы умножить матрицу 200x248 на матрицу 248x333 на 8 потоках, вам нужно дополнительно разделить один из измерений на 8, чтобы обеспечить параллелизм.