bartasova_ksenia_lab_1 ready

This commit is contained in:
2025-03-14 18:37:32 +04:00
parent 2e06257c82
commit 70f8e9724d
6 changed files with 202 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ForkJoinMatrixProcessor {
private static class MatrixTask extends RecursiveAction {
private final double[][] matrix;
private final int startRow, endRow;
private final double average;
MatrixTask(double[][] matrix, int startRow, int endRow, double average) {
this.matrix = matrix;
this.startRow = startRow;
this.endRow = endRow;
this.average = average;
}
@Override
protected void compute() {
if (endRow - startRow <= 10) { // Базовый случай: обрабатываем небольшой блок
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < matrix[i].length; j++) {
matrix[i][j] /= average;
}
}
} else { // Рекурсивный случай: разбиваем задачу на две части
int mid = (startRow + endRow) / 2;
invokeAll(
new MatrixTask(matrix, startRow, mid, average),
new MatrixTask(matrix, mid, endRow, average)
);
}
}
}
public static void process(double[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
// Вычисляем среднее арифметическое
double sum = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sum += matrix[i][j];
}
}
double average = sum / (rows * cols);
// Создаем и запускаем задачу в ForkJoinPool
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new MatrixTask(matrix, 0, rows, average));
pool.shutdown();
}
}

View File

@@ -0,0 +1,38 @@
public class Main {
public static void main(String[] args) throws InterruptedException {
int rows = 1000;
int cols = 1000;
double[][] matrix = MatrixGenerator.generateMatrix(rows, cols);
// Однопоточный вариант
double[][] singleThreadedMatrix = copyMatrix(matrix);
long startTime = System.nanoTime();
SingleThreadedMatrixProcessor.process(singleThreadedMatrix);
long endTime = System.nanoTime();
System.out.println("Single-threaded: " + (endTime - startTime) / 1e9 + " сек");
// Параллельный вариант с ThreadPoolExecutor
double[][] threadPoolMatrix = copyMatrix(matrix);
startTime = System.nanoTime();
ThreadPoolMatrixProcessor.process(threadPoolMatrix, 4); // 4 потока
endTime = System.nanoTime();
System.out.println("ThreadPoolExecutor: " + (endTime - startTime) / 1e9 + " сек");
// Параллельный вариант с ForkJoinPool
double[][] forkJoinMatrix = copyMatrix(matrix);
startTime = System.nanoTime();
ForkJoinMatrixProcessor.process(forkJoinMatrix);
endTime = System.nanoTime();
System.out.println("ForkJoinPool: " + (endTime - startTime) / 1e9 + " сек");
}
private static double[][] copyMatrix(double[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
double[][] copy = new double[rows][cols];
for (int i = 0; i < rows; i++) {
System.arraycopy(matrix[i], 0, copy[i], 0, cols);
}
return copy;
}
}

View File

@@ -0,0 +1,14 @@
import java.util.Random;
public class MatrixGenerator {
public static double[][] generateMatrix(int rows, int cols) {
double[][] matrix = new double[rows][cols];
Random random = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = random.nextDouble() * 100; // Заполняем случайными числами
}
}
return matrix;
}
}

View File

@@ -0,0 +1,22 @@
public class SingleThreadedMatrixProcessor {
public static void process(double[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
// Вычисляем среднее арифметическое
double sum = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sum += matrix[i][j];
}
}
double average = sum / (rows * cols);
// Делим каждый элемент на среднее
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] /= average;
}
}
}
}

View File

@@ -0,0 +1,36 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPoolMatrixProcessor {
public static void process(double[][] matrix, int threadPoolSize) throws InterruptedException {
int rows = matrix.length;
int cols = matrix[0].length;
// Вычисляем среднее арифметическое
double sum = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sum += matrix[i][j];
}
}
double average = sum / (rows * cols);
// Создаем пул потоков
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
// Обрабатываем каждую строку в отдельном потоке
for (int i = 0; i < rows; i++) {
final int row = i;
executor.submit(() -> {
for (int j = 0; j < cols; j++) {
matrix[row][j] /= average;
}
});
}
// Завершаем работу пула
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
}
}

View File

@@ -0,0 +1,39 @@
# Лабораторная работа №1
Разработка многопоточного приложения с использованием Java Concurrency согласно варианту задания.
Необходимо:
1. Разработать однопоточный вариант алгоритма и замерить время его работы.
2. Разработать параллельный вариант алгоритма с использованием ThreadPoolExecutor и замерить время его работы
3. Разработать параллельный вариант алгоритма с использованием ForkJoinPoll и замерить время его работы.
Массив генерируется до работы всех вариантов алгоритмов. Все три алгоритма обрабатывают три одинаковых массива.
## Вариант 3
Разделить элементы матрицы на среднее арифметическое всех ее элементов.
### Как запустить лабораторную работу:
javac Main.java компилирует исходный код
java Main команда запускает скомпилированный класс
### Какие технологии использовали:
java.util.concurrent используется для работы с многопоточностью и параллельными алгоритмами.
- ExecutorService и Executors используются для управления пулами потоков и выполнения задач.
- TimeUnit помогает работать с временными интервалами.
- ForkJoinPool, RecursiveAction и RecursiveTask используются для параллельного выполнения задач, которые можно разбить на более мелкие подзадачи.
### Как работает программа:
1. Генерируем матрицу размером 1000*1000
2. Создаем три копии исходной матрицы
3. Класс SingleThreadedMatrixProcessor обрабатывает матрицу в одном потоке
4. Класс ThreadPoolMatrixProcessor обрабатывает матрицу с использованием пула потоков: создается пул потоков, каждая строка матрицы обрабатывается в отдельном потоке
5. Класс ForkJoinMatrixProcessor обрабатывает матрицу с использованием ForkJoinPool и рекурсивного разделения задачи: если блок большой, он разделяется на две части, и каждая часть обрабатывается рекурсивно
6. Выводятся результаты времени выполнения для каждого из трех подходов.
### Тесты:
Single-threaded: 0.015592711 сек
ThreadPoolExecutor: 0.024355768 сек
ForkJoinPool: 0.01131473 сек
### Вывод:
ForkJoinPool — самый быстрый. Однопоточный алгоритм — быстрее, чем ThreadPoolExecutor, но медленнее, чем ForkJoinPool. ThreadPoolExecutor — самый медленный в данном случае.