Files
SSPR_25/khasyanov_aidar_lab_1/MinDivisionTask.java
2025-03-14 22:53:37 +04:00

227 lines
9.5 KiB
Java

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
public class MinDivisionTask {
static double[][] mainArray = new double[4000][4000];
static double[][] bufferArray = new double[mainArray.length][mainArray.length];
static final int FRONTIER = 5000; // Порог разбиения
static final int THREADS = 2; // Кол-во потоков
static int countOftests = 20; // Кол-во тестов
public static void main(String[] args) {
DoTests();
}
public static void DoTests() {
long SingleThreadedTimeSum = 0;
long ThreadPoolExecutorTimeSum = 0;
long ForkJoinPoolTimeSum = 0;
int count = 0;
Random random = new Random();
while (count != countOftests) {
count += 1;
for (int i = 0; i < mainArray.length; i++) {
for (int j = 0; j < mainArray.length; j++) {
mainArray[i][j] = random.nextInt(-100,100);
bufferArray[i][j] = mainArray[i][j];
}
}
//PrintLogMatrix(mainArray); System.out.println();
// Однопоточный алгоритм
long SingleThreadedTime = ComputeAndPrintDuration("SingleThreadedAlgorithm");
SingleThreadedTimeSum += SingleThreadedTime;
// Многопоточный алгоритм
long ThreadPoolExecutorTime = ComputeAndPrintDuration("ThreadPoolExecutorAlgorithm");
ThreadPoolExecutorTimeSum += ThreadPoolExecutorTime;
// ForkJoinPool-алгоритм
long ForkJoinPoolTime = ComputeAndPrintDuration("ForkJoinPoolAlgorithm");
ForkJoinPoolTimeSum += ForkJoinPoolTime;
System.out.println("{Тест "+ count + "} " + "SingleThreadedTime: " + SingleThreadedTime +
" ThreadPoolExecutorTime: " + ThreadPoolExecutorTime + " ForkJoinPoolTime: " + ForkJoinPoolTime);
}
System.out.println("SingleThreadedTime: " + SingleThreadedTimeSum/countOftests);
System.out.println("ThreadPoolExecutorTime: " + ThreadPoolExecutorTimeSum/countOftests);
System.out.println("ForkJoinPoolTime: " + ForkJoinPoolTimeSum/countOftests);
}
public static void CopyArray() {
for (int i = 0; i < mainArray.length; i++) {
for (int j = 0; j < mainArray.length; j++) mainArray[i][j] = bufferArray[i][j];
}
}
public static void PrintLogMatrix(double[][] mainArray) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(mainArray[i][j] + " ");
}
System.out.println();
}
}
public static long ComputeAndPrintDuration(String typeOfAlgoritm) {
long startTime = 0, endTime = 0, duration;
switch (typeOfAlgoritm) {
case "SingleThreadedAlgorithm":
startTime = System.nanoTime();
SingleThreadedAlgorithm(mainArray);
endTime = System.nanoTime();
break;
case "ThreadPoolExecutorAlgorithm":
startTime = System.nanoTime();
ThreadPoolExecutorAlgorithm(mainArray);
endTime = System.nanoTime();
break;
case "ForkJoinPoolAlgorithm":
startTime = System.nanoTime();
ForkJoinPoolAlgorithm(mainArray);
endTime = System.nanoTime();
break;
default:
break;
}
duration = (endTime - startTime) / 1000000;
//System.out.println("Время выполнения: " + (duration) + " мс\n");
CopyArray();
return duration;
}
public static void SingleThreadedAlgorithm(double[][] mainArray) {
//System.out.println("Однопоточный алгоритм");
double min = Double.MAX_VALUE;
for (int i = 0; i < mainArray.length; i++) {
for (int j = 0; j < mainArray.length; j++) {
if(min > mainArray[i][j]) min = mainArray[i][j];
}
}
//System.out.println("Наименьший элемент: " + min);
for (int i = 0; i < mainArray.length; i++) {
for (int j = 0; j < mainArray.length; j++) {
mainArray[i][j] = mainArray[i][j] / min;
}
}
//PrintLogMatrix(mainArray);
}
public static void ThreadPoolExecutorAlgorithm(double[][] mainArray) {
//System.out.println("ThreadPoolExecutorAlgorithm");
int size = mainArray.length;
ExecutorService executor = Executors.newFixedThreadPool(THREADS); // Создаем пул потоков
AtomicLong globalMin = new AtomicLong(Long.MAX_VALUE);
// Вычисление суммы элементов массива
for (int t = 0; t < THREADS; t++) {
final int startRow = t * (size / THREADS); // Начало данного потока
final int endRow = (t == THREADS - 1) ? size : (t + 1) * (size / THREADS); // Конец данного потока
executor.submit(() -> {
double localMin = Double.MAX_VALUE;
// Вычисление суммы в рамках выделенного потоку диапазона строк
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < size; j++) {
if(localMin > mainArray[i][j]) localMin = mainArray[i][j];
}
}
// Вычисление наименьшего элемента глобально
long finalLocalMin = (long)localMin;
globalMin.updateAndGet(v -> Math.min(v, finalLocalMin));
});
}
// Деление элементов массива на наименьшее значение
for (int t = 0; t < THREADS; t++) {
final int startRow = t * (size / THREADS); // Начало данного потока
final int endRow = (t == THREADS - 1) ? size : (t + 1) * (size / THREADS); // Конец данного потока
executor.submit(() -> {
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < size; j++) {
mainArray[i][j] /= globalMin.get();
}
}
});
}
executor.shutdown();
while (!executor.isTerminated()) { /* Ожидание завершения всех задач */ }
double min = globalMin.get();
//System.out.println("Наименьший элемент: " + min);
//PrintLogMatrix(mainArray);
}
public static void ForkJoinPoolAlgorithm(double[][] mainArray) {
//System.out.println("ForkJoinPoolAlgorithm");
int size = mainArray.length;
ForkJoinPool forkJoinPool = new ForkJoinPool();
// Вычисление наименьшего элемента
MinTask minTask = new MinTask(mainArray, 0, size);
double min = forkJoinPool.invoke(minTask);
//System.out.println("Наименьший элемент: " + min);
// Деление массива на наименьший элемент
forkJoinPool.invoke(new DivisionTask(mainArray, 0, size, min));
forkJoinPool.shutdown();
//PrintLogMatrix(mainArray);
}
static class MinTask extends RecursiveTask<Double> {
private final double[][] mainArray;
private final int startRow, endRow;
MinTask(double[][] mainArray, int startRow, int endRow) {
this.mainArray = mainArray;
this.startRow = startRow;
this.endRow = endRow;
}
@Override
protected Double compute() {
if (endRow - startRow <= FRONTIER) {
double min = Double.MAX_VALUE;
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < mainArray[i].length; j++) {
if(min > mainArray[i][j]) min = mainArray[i][j];
}
}
return (Double) min;
} else {
int midRow = (startRow + endRow) / 2;
MinTask top = new MinTask(mainArray, startRow, midRow);
MinTask bottom = new MinTask(mainArray, midRow, endRow);
top.fork();
double bottomResult = bottom.compute();
return (Double) Math.min(top.join(), (long)bottomResult);
}
}
}
static class DivisionTask extends RecursiveAction {
private final double[][] mainArray;
private final int startRow, endRow;
private final double min;
DivisionTask(double[][] mainArray, int startRow, int endRow, double min) {
this.mainArray = mainArray;
this.startRow = startRow;
this.endRow = endRow;
this.min = min;
}
@Override
protected void compute() {
if (endRow - startRow <= FRONTIER) {
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < mainArray[i].length; j++) {
mainArray[i][j] /= min;
}
}
} else {
int midRow = (startRow + endRow) / 2;
invokeAll(new DivisionTask(mainArray, startRow, midRow, min),
new DivisionTask(mainArray, midRow, endRow, min));
}
}
}
}