diff --git a/afanasev_dmitry_lab_5/README.md b/afanasev_dmitry_lab_5/README.md new file mode 100644 index 0000000..21c6215 --- /dev/null +++ b/afanasev_dmitry_lab_5/README.md @@ -0,0 +1,31 @@ +# Лабораторная работа 5 + +## Описание +Задание заключается в реализации алгоритмов умножения больших квадратных матриц. Необходимо разработать два алгоритма: последовательный и параллельный. А также провести бенчмарки, а затем описать результаты в отчете. + +**100x100 матрица**: +- **4 потока** — наилучший результат. +- **10 потоков** — медленнее на почти в половину. +- **6 и 8 потоков** — хуже 4 потоков. +- **1 и 2 потока** — значительно медленнее. + +**300x300 матрица**: +- **4 потока** — лучший результат. +- **8 потоков** — чуть хуже. +- **10 потоков** — медленнее. +- **1 и 2 потока** — значительно медленнее. + +**500x500 матрица**: +- **8 потоков** — лучший результат. +- **6 и 10 потоков** — немного хуже. +- **4 потока** — значительно медленнее. +- **1 поток** — самый медленный. + +**Ссылка на демонстрацию работы программы**: https://vk.com/video215756667_456239455?list=ln-z7zFcpvxLexJd3f8ss + +**Вывод**: +- Если операция сложнее, рост производительности происходит с увеличением числа потоков. +- Слишком много потоков увеличивает накладные расходы (например, 10 потоков). Это может быть связано, например, с: +1. **Переключением контекстов**: Когда потоков больше, чем ядер процессора, операционная система часто переключает контексты, что занимает время. +2. **Конкуренцией за ресурсы**: Много потоков конкурируют за ограниченные ресурсы, такие как процессорное время и кэш. +3. **Управлением потоками**: С увеличением числа потоков растёт нагрузка на систему, связанную с их созданием, управлением и завершением. diff --git a/afanasev_dmitry_lab_5/main/.gitignore b/afanasev_dmitry_lab_5/main/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/afanasev_dmitry_lab_5/main/.gitignore @@ -0,0 +1,29 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/afanasev_dmitry_lab_5/main/src/MatrixMultiplier.java b/afanasev_dmitry_lab_5/main/src/MatrixMultiplier.java new file mode 100644 index 0000000..fcee2e4 --- /dev/null +++ b/afanasev_dmitry_lab_5/main/src/MatrixMultiplier.java @@ -0,0 +1,120 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class MatrixMultiplier { + private final int[][] matrixA; + private final int[][] matrixB; + private final int[][] result; + private final int size; + + public MatrixMultiplier(int size) { + this.size = size; + this.matrixA = generateMatrix(size); + this.matrixB = generateMatrix(size); + this.result = new int[size][size]; + } + + private int[][] generateMatrix(int size) { + int[][] matrix = new int[size][size]; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + matrix[i][j] = (int) (Math.random() * 10); + } + } + return matrix; + } + + public void multiplySequential() { + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + result[i][j] += matrixA[i][k] * matrixB[k][j]; + } + } + } + } + + public void multiplyParallel(int numThreads) throws InterruptedException { + if (numThreads == 1) { + multiplySequential(); + return; + } + + ExecutorService executor = Executors.newFixedThreadPool(numThreads); + int chunkSize = (int) Math.ceil((double) size / numThreads); + + for (int thread = 0; thread < numThreads; thread++) { + final int startRow = thread * chunkSize; + final int endRow = Math.min(startRow + chunkSize, size); + + executor.submit(() -> { + for (int i = startRow; i < endRow; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + result[i][j] += matrixA[i][k] * matrixB[k][j]; + } + } + } + }); + } + executor.shutdown(); + executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } + + private void resetResult() { + for (int i = 0; i < size; i++) { + Arrays.fill(result[i], 0); + } + } + + static class Result { + int threads; + long time; + + Result(int threads, long time) { + this.threads = threads; + this.time = time; + } + } + + public static void main(String[] args) throws InterruptedException { + int[] matrixSizes = {100, 300, 500}; + int[] threadCounts = {1, 2, 4, 6, 8, 10}; + int runs = 5; // количество прогонов + + for (int size : matrixSizes) { + System.out.println("\nРазмер матрицы: " + size + "x" + size); + MatrixMultiplier multiplier = new MatrixMultiplier(size); + List results = new ArrayList<>(); + + for (int threads : threadCounts) { + long totalDuration = 0; + + for (int run = 0; run < runs; run++) { + multiplier.resetResult(); + long startTime = System.nanoTime(); + multiplier.multiplyParallel(threads); + long endTime = System.nanoTime(); + + totalDuration += (endTime - startTime); + } + + long averageDuration = totalDuration / runs; + results.add(new Result(threads, averageDuration)); + } + + // Сортировка по времени выполнения + results.sort(Comparator.comparingLong(r -> r.time)); + + System.out.println("Результаты (среднее время за " + runs + " прогонов):"); + for (Result result : results) { + System.out.printf("Потоки: %d, среднее время: %d нс\n", result.threads, result.time); + } + } + } +}