commit 2c6bed75898bbcfefbc611612ef7b9bcac0f9911 Author: LivelyPuer Date: Tue Mar 4 22:04:34 2025 +0400 init diff --git a/main/pom.xml b/main/pom.xml new file mode 100644 index 0000000..0236b9c --- /dev/null +++ b/main/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.0 + + + com.example + matrix-main-service + 0.0.1-SNAPSHOT + matrix-main-service + Main service for distributed matrix minimum search + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-webflux + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/main/src/main/java/com/example/matrix/MatrixMainApplication.java b/main/src/main/java/com/example/matrix/MatrixMainApplication.java new file mode 100644 index 0000000..745e4e1 --- /dev/null +++ b/main/src/main/java/com/example/matrix/MatrixMainApplication.java @@ -0,0 +1,11 @@ +package com.example.matrix; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MatrixMainApplication { + public static void main(String[] args) { + SpringApplication.run(MatrixMainApplication.class, args); + } +} \ No newline at end of file diff --git a/main/src/main/java/com/example/matrix/client/WorkerServiceClient.java b/main/src/main/java/com/example/matrix/client/WorkerServiceClient.java new file mode 100644 index 0000000..75ff4e1 --- /dev/null +++ b/main/src/main/java/com/example/matrix/client/WorkerServiceClient.java @@ -0,0 +1,28 @@ +package com.example.matrix.client; + +import com.example.matrix.model.Matrix; +import com.example.matrix.model.MinResult; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +@Service +public class WorkerServiceClient { + + private final WebClient webClient; + + public WorkerServiceClient(@Value("${worker.service.url}") String workerServiceUrl) { + this.webClient = WebClient.builder() + .baseUrl(workerServiceUrl) + .build(); + } + + public Mono findMinimum(Matrix matrix) { + return webClient.post() + .uri("/matrix/min") + .bodyValue(matrix) + .retrieve() + .bodyToMono(MinResult.class); + } +} \ No newline at end of file diff --git a/main/src/main/java/com/example/matrix/controller/MatrixController.java b/main/src/main/java/com/example/matrix/controller/MatrixController.java new file mode 100644 index 0000000..fb9cc5f --- /dev/null +++ b/main/src/main/java/com/example/matrix/controller/MatrixController.java @@ -0,0 +1,66 @@ +package com.example.matrix.controller; + +import com.example.matrix.model.Matrix; +import com.example.matrix.model.MinResult; +import com.example.matrix.service.MatrixService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/matrix") +@RequiredArgsConstructor +public class MatrixController { + + private final MatrixService matrixService; + + @PostMapping("/generate") + public Matrix generateMatrix(@RequestParam int rows, @RequestParam int cols) { + return matrixService.generateMatrix(rows, cols); + } + + @PostMapping("/min/sequential") + public MinResult findMinimumSequential(@RequestBody Matrix matrix) { + return matrixService.findMinimumSequential(matrix); + } + + @PostMapping("/min/parallel") + public MinResult findMinimumParallel(@RequestBody Matrix matrix) throws ExecutionException, InterruptedException { + return matrixService.findMinimumParallel(matrix); + } + + // Простой эндпоинт для замера времени выполнения + @PostMapping("/benchmark") + public String benchmark(@RequestParam int rows, @RequestParam int cols, @RequestParam int iterations) throws ExecutionException, InterruptedException { + Matrix matrix = matrixService.generateMatrix(rows, cols); + + long totalSequentialTime = 0; + long totalParallelTime = 0; + + for (int i = 0; i < iterations; i++) { + MinResult sequentialResult = matrixService.findMinimumSequential(matrix); + MinResult parallelResult = matrixService.findMinimumParallel(matrix); + + totalSequentialTime += sequentialResult.getProcessingTimeMs(); + totalParallelTime += parallelResult.getProcessingTimeMs(); + + // Проверка корректности результатов + if (sequentialResult.getMinValue() != parallelResult.getMinValue()) { + return "Error: different minimum values found. Sequential: " + + sequentialResult.getMinValue() + ", Parallel: " + parallelResult.getMinValue(); + } + } + + double avgSequentialTime = (double) totalSequentialTime / iterations; + double avgParallelTime = (double) totalParallelTime / iterations; + double speedup = avgSequentialTime / avgParallelTime; + + return String.format("Benchmark results (average over %d iterations):\n" + + "Matrix size: %dx%d\n" + + "Sequential execution time: %.2f ms\n" + + "Parallel execution time: %.2f ms\n" + + "Speedup: %.2fx", + iterations, rows, cols, avgSequentialTime, avgParallelTime, speedup); + } +} diff --git a/main/src/main/java/com/example/matrix/model/Matrix.java b/main/src/main/java/com/example/matrix/model/Matrix.java new file mode 100644 index 0000000..9f2d3bd --- /dev/null +++ b/main/src/main/java/com/example/matrix/model/Matrix.java @@ -0,0 +1,45 @@ +package com.example.matrix.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Matrix { + private int[][] data; + private int rows; + private int cols; + + public Matrix(int rows, int cols) { + this.rows = rows; + this.cols = cols; + this.data = new int[rows][cols]; + } + + // Метод для заполнения матрицы случайными значениями + public void fillRandom(int min, int max) { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + data[i][j] = min + (int) (Math.random() * (max - min + 1)); + } + } + } + + // Получение подматрицы (части матрицы) + public Matrix getSubMatrix(int startRow, int endRow) { + if (startRow < 0 || endRow > rows || startRow >= endRow) { + throw new IllegalArgumentException("Invalid row range"); + } + + int subRows = endRow - startRow; + Matrix subMatrix = new Matrix(subRows, cols); + + for (int i = 0; i < subRows; i++) { + System.arraycopy(data[startRow + i], 0, subMatrix.data[i], 0, cols); + } + + return subMatrix; + } +} \ No newline at end of file diff --git a/main/src/main/java/com/example/matrix/model/MinResult.java b/main/src/main/java/com/example/matrix/model/MinResult.java new file mode 100644 index 0000000..1a5c580 --- /dev/null +++ b/main/src/main/java/com/example/matrix/model/MinResult.java @@ -0,0 +1,22 @@ +package com.example.matrix.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MinResult { + private int minValue; + private int row; + private int col; + private long processingTimeMs; + + public MinResult(int minValue) { + this.minValue = minValue; + this.row = -1; + this.col = -1; + this.processingTimeMs = 0; + } +} diff --git a/main/src/main/java/com/example/matrix/service/MatrixService.java b/main/src/main/java/com/example/matrix/service/MatrixService.java new file mode 100644 index 0000000..b1a6b22 --- /dev/null +++ b/main/src/main/java/com/example/matrix/service/MatrixService.java @@ -0,0 +1,104 @@ +package com.example.matrix.service; + +import com.example.matrix.client.WorkerServiceClient; +import com.example.matrix.model.Matrix; +import com.example.matrix.model.MinResult; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@Service +@RequiredArgsConstructor +public class MatrixService { + + private final WorkerServiceClient workerServiceClient; + + // Метод для генерации матрицы заданного размера + public Matrix generateMatrix(int rows, int cols) { + Matrix matrix = new Matrix(rows, cols); + matrix.fillRandom(-100, 100); // Заполняем случайными значениями от -100 до 100 + return matrix; + } + + // Поиск минимального элемента в матрице (последовательный алгоритм для сравнения) + public MinResult findMinimumSequential(Matrix matrix) { + long startTime = System.currentTimeMillis(); + + int minValue = Integer.MAX_VALUE; + int minRow = -1; + int minCol = -1; + + for (int i = 0; i < matrix.getRows(); i++) { + for (int j = 0; j < matrix.getCols(); j++) { + if (matrix.getData()[i][j] < minValue) { + minValue = matrix.getData()[i][j]; + minRow = i; + minCol = j; + } + } + } + + long processingTime = System.currentTimeMillis() - startTime; + return new MinResult(minValue, minRow, minCol, processingTime); + } + + // Параллельный поиск минимума с использованием двух сервисов + public MinResult findMinimumParallel(Matrix matrix) throws ExecutionException, InterruptedException { + long startTime = System.currentTimeMillis(); + + // Разделяем матрицу на две части + int halfRows = matrix.getRows() / 2; + Matrix firstHalf = matrix.getSubMatrix(0, halfRows); + Matrix secondHalf = matrix.getSubMatrix(halfRows, matrix.getRows()); + + // Находим минимум в первой половине локально + CompletableFuture localFuture = CompletableFuture.supplyAsync(() -> { + int minValue = Integer.MAX_VALUE; + int minRow = -1; + int minCol = -1; + + for (int i = 0; i < firstHalf.getRows(); i++) { + for (int j = 0; j < firstHalf.getCols(); j++) { + if (firstHalf.getData()[i][j] < minValue) { + minValue = firstHalf.getData()[i][j]; + minRow = i; + minCol = j; + } + } + } + + return new MinResult(minValue, minRow, minCol, 0); + }); + + // Находим минимум во второй половине через Worker Service + CompletableFuture remoteFuture = workerServiceClient.findMinimum(secondHalf) + .map(result -> { + // Корректируем индекс строки (добавляем смещение) + if (result.getRow() >= 0) { + result.setRow(result.getRow() + halfRows); + } + return result; + }) + .toFuture(); + + // Ждем завершения обоих вычислений и выбираем минимальный результат + CompletableFuture combinedFuture = localFuture.thenCombine(remoteFuture, (local, remote) -> { + if (local.getMinValue() <= remote.getMinValue()) { + return local; + } else { + return remote; + } + }); + + MinResult result = combinedFuture.get(); + long processingTime = System.currentTimeMillis() - startTime; + result.setProcessingTimeMs(processingTime); + + return result; + } +} diff --git a/main/src/main/resources/application.properties b/main/src/main/resources/application.properties new file mode 100644 index 0000000..2f76d2e --- /dev/null +++ b/main/src/main/resources/application.properties @@ -0,0 +1,2 @@ +server.port=8080 +worker.service.url=http://worker-vm:8081 \ No newline at end of file diff --git a/worker/pom.xml b/worker/pom.xml new file mode 100644 index 0000000..22ae079 --- /dev/null +++ b/worker/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.0 + + + com.example + matrix-worker-service + 0.0.1-SNAPSHOT + matrix-worker-service + Worker service for distributed matrix minimum search + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/worker/src/main/java/com/example/matrix/MatrixWorkerApplication.java b/worker/src/main/java/com/example/matrix/MatrixWorkerApplication.java new file mode 100644 index 0000000..9d5c041 --- /dev/null +++ b/worker/src/main/java/com/example/matrix/MatrixWorkerApplication.java @@ -0,0 +1,11 @@ +package com.example.matrix; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MatrixWorkerApplication { + public static void main(String[] args) { + SpringApplication.run(MatrixWorkerApplication.class, args); + } +} \ No newline at end of file diff --git a/worker/src/main/java/com/example/matrix/controller/WorkerController.java b/worker/src/main/java/com/example/matrix/controller/WorkerController.java new file mode 100644 index 0000000..48346b4 --- /dev/null +++ b/worker/src/main/java/com/example/matrix/controller/WorkerController.java @@ -0,0 +1,23 @@ +package com.example.matrix.controller; + +import com.example.matrix.model.Matrix; +import com.example.matrix.model.MinResult; +import com.example.matrix.service.WorkerService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/matrix") +@RequiredArgsConstructor +public class WorkerController { + + private final WorkerService workerService; + + @PostMapping("/min") + public MinResult findMinimum(@RequestBody Matrix matrix) { + return workerService.findMinimum(matrix); + } +} \ No newline at end of file diff --git a/worker/src/main/java/com/example/matrix/model/Matrix.java b/worker/src/main/java/com/example/matrix/model/Matrix.java new file mode 100644 index 0000000..9f2d3bd --- /dev/null +++ b/worker/src/main/java/com/example/matrix/model/Matrix.java @@ -0,0 +1,45 @@ +package com.example.matrix.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Matrix { + private int[][] data; + private int rows; + private int cols; + + public Matrix(int rows, int cols) { + this.rows = rows; + this.cols = cols; + this.data = new int[rows][cols]; + } + + // Метод для заполнения матрицы случайными значениями + public void fillRandom(int min, int max) { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + data[i][j] = min + (int) (Math.random() * (max - min + 1)); + } + } + } + + // Получение подматрицы (части матрицы) + public Matrix getSubMatrix(int startRow, int endRow) { + if (startRow < 0 || endRow > rows || startRow >= endRow) { + throw new IllegalArgumentException("Invalid row range"); + } + + int subRows = endRow - startRow; + Matrix subMatrix = new Matrix(subRows, cols); + + for (int i = 0; i < subRows; i++) { + System.arraycopy(data[startRow + i], 0, subMatrix.data[i], 0, cols); + } + + return subMatrix; + } +} \ No newline at end of file diff --git a/worker/src/main/java/com/example/matrix/model/MinResult.java b/worker/src/main/java/com/example/matrix/model/MinResult.java new file mode 100644 index 0000000..ced62e4 --- /dev/null +++ b/worker/src/main/java/com/example/matrix/model/MinResult.java @@ -0,0 +1,22 @@ +package com.example.matrix.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MinResult { + private int minValue; + private int row; + private int col; + private long processingTimeMs; + + public MinResult(int minValue) { + this.minValue = minValue; + this.row = -1; + this.col = -1; + this.processingTimeMs = 0; + } +} \ No newline at end of file diff --git a/worker/src/main/java/com/example/matrix/service/WorkerService.java b/worker/src/main/java/com/example/matrix/service/WorkerService.java new file mode 100644 index 0000000..a685ff5 --- /dev/null +++ b/worker/src/main/java/com/example/matrix/service/WorkerService.java @@ -0,0 +1,30 @@ +package com.example.matrix.service; + +import com.example.matrix.model.Matrix; +import com.example.matrix.model.MinResult; +import org.springframework.stereotype.Service; + +@Service +public class WorkerService { + + public MinResult findMinimum(Matrix matrix) { + long startTime = System.currentTimeMillis(); + + int minValue = Integer.MAX_VALUE; + int minRow = -1; + int minCol = -1; + + for (int i = 0; i < matrix.getRows(); i++) { + for (int j = 0; j < matrix.getCols(); j++) { + if (matrix.getData()[i][j] < minValue) { + minValue = matrix.getData()[i][j]; + minRow = i; + minCol = j; + } + } + } + + long processingTime = System.currentTimeMillis() - startTime; + return new MinResult(minValue, minRow, minCol, processingTime); + } +} \ No newline at end of file diff --git a/worker/src/main/resources/application.properties b/worker/src/main/resources/application.properties new file mode 100644 index 0000000..bafddce --- /dev/null +++ b/worker/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8081 \ No newline at end of file