Merge pull request 'PIBD-22-lyakhov_timofey_lab_1_ready' (#42) from funa4i/SSPR_25:lyakhov_timofey_lab_1 into main
Reviewed-on: #42
This commit was merged in pull request #42.
This commit is contained in:
4
lyakhov_timofey_lab_1/.dockerfile
Normal file
4
lyakhov_timofey_lab_1/.dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM openjdk:21-jdk-slim
|
||||||
|
COPY target/sspr-1.0-SNAPSHOT.jar app.jar
|
||||||
|
|
||||||
|
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
||||||
186
lyakhov_timofey_lab_1/README.md
Normal file
186
lyakhov_timofey_lab_1/README.md
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
# Лабораторная работа №1
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Программа вычисляет сумму произведений строк квадратной матрицы с использованием трех подходов:
|
||||||
|
|
||||||
|
- Однопоточная реализация
|
||||||
|
- Многопоточная реализация с использованием ThreadPool
|
||||||
|
- Реализация с использованием ForkJoinPool
|
||||||
|
|
||||||
|
Цель — сравнить эффективность различных способов многопоточной обработки данных и замерить время выполнения для каждого подхода.
|
||||||
|
|
||||||
|
## Как запустить лабораторную работу
|
||||||
|
|
||||||
|
1. Соберите проект и получите `.jar` файл:
|
||||||
|
```bash
|
||||||
|
mvn package
|
||||||
|
```
|
||||||
|
Либо перейдите сразу к шагу 2, если `.jar` уже собран.
|
||||||
|
|
||||||
|
2. Соберите Docker-образ:
|
||||||
|
```bash
|
||||||
|
docker build -t app -f .dockerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Запустите контейнер:
|
||||||
|
```bash
|
||||||
|
docker run -i app
|
||||||
|
```
|
||||||
|
|
||||||
|
## Используемые технологии
|
||||||
|
|
||||||
|
- **Java**
|
||||||
|
- **Maven** — для сборки проекта
|
||||||
|
- **Docker** — для упаковки и запуска приложения в контейнере
|
||||||
|
- **Параллельное программирование**:
|
||||||
|
- `ExecutorService` (ThreadPool)
|
||||||
|
- `ForkJoinPool` (пул задач с рекурсивным делением данных)
|
||||||
|
|
||||||
|
## Что делает программа
|
||||||
|
|
||||||
|
- Заполняет матрицу случайными числами от 1 до 100.
|
||||||
|
- Вычисляет сумму произведений элементов в каждой строке матрицы тремя способами:
|
||||||
|
1. **Однопоточная реализация** — классический линейный перебор строк.
|
||||||
|
2. **ThreadPool** — распределение строк по пулу потоков.
|
||||||
|
3. **ForkJoinPool** — разбиение задачи на подзадачи с использованием `RecursiveTask`.
|
||||||
|
- Для каждого способа выводит время выполнения в наносекундах.
|
||||||
|
```java
|
||||||
|
|
||||||
|
public static void calculateSumOfRow() { // Фнукция подсчета в одном потоке
|
||||||
|
LocalDateTime startTime = LocalDateTime.now();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
int sum = 0;
|
||||||
|
for (int[] ints : matrix) {
|
||||||
|
int product = 1;
|
||||||
|
for (int anInt : ints) {
|
||||||
|
product *= anInt;
|
||||||
|
}
|
||||||
|
sum += product;
|
||||||
|
}
|
||||||
|
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения в одном потоке: \t" + st);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void calculateSumOfRowWithThreadPool() { // Фнукция подсчета с помощью ThreadPool
|
||||||
|
int sum = 0;
|
||||||
|
int numThreads = Runtime.getRuntime().availableProcessors(); // Определение количества потоков на основании процессора
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
|
||||||
|
List<Future<Integer>> futures = new ArrayList<>();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
for (int i = 0; i < matrix.length; i++) { // Создание задач выполнения
|
||||||
|
final int row = i;
|
||||||
|
futures.add(executor.submit(() -> {
|
||||||
|
int product = 1;
|
||||||
|
for (int j = 0; j < matrix[row].length; j++) {
|
||||||
|
product *= matrix[row][j];
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Future<Integer> future : futures) { // Подсчет всех значений
|
||||||
|
try {
|
||||||
|
sum += future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения с ThreadPool: \t\t" + st);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void calculateSumOfRowWithForkPool(){ // ПОдсчет через ForkPool
|
||||||
|
|
||||||
|
PartTask pt = new PartTask(matrix, 0, size + 1); // Создание сущности парта
|
||||||
|
ForkJoinPool forkJoinPool = new ForkJoinPool();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
forkJoinPool.invoke(pt);
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения с ForkJoinPool: \t" + st);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
class PartTask extends RecursiveTask<Integer> { // Класс задачи
|
||||||
|
|
||||||
|
private final int[][] matrix;
|
||||||
|
private final int start, stop;
|
||||||
|
|
||||||
|
public PartTask(int[][] matrix, int start, int stop) {
|
||||||
|
this.matrix = matrix;
|
||||||
|
this.start = start;
|
||||||
|
this.stop = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer compute() { // Вычисление части парта(Использование рекурсий)
|
||||||
|
if (start + 1 == stop) {
|
||||||
|
return Arrays.stream(matrix[start]).sum();
|
||||||
|
}
|
||||||
|
PartTask p1 = new PartTask(matrix, start, (start + stop) / 2);
|
||||||
|
PartTask p2 = new PartTask(matrix, (start + stop) / 2, stop);
|
||||||
|
p1.fork();
|
||||||
|
p2.fork();
|
||||||
|
return p1.join() + p2.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Особенности кода
|
||||||
|
|
||||||
|
- Используется замер времени выполнения с помощью `System.nanoTime()`.
|
||||||
|
- ThreadPool автоматически подстраивается под количество доступных ядер CPU.
|
||||||
|
- Реализация с ForkJoinPool демонстрирует работу паттерна divide-and-conquer (разделяй и властвуй).
|
||||||
|
- Для ForkJoinPool реализован собственный класс `PartTask`, унаследованный от `RecursiveTask<Integer>`.
|
||||||
|
|
||||||
|
## Тесты (Примеры ввода и вывода)
|
||||||
|
|
||||||
|
### Тест 1:
|
||||||
|
**Ввод:**
|
||||||
|
```
|
||||||
|
Введите размер матрицы (от 2 до 1000): 10
|
||||||
|
```
|
||||||
|
**Вывод:**
|
||||||
|
```
|
||||||
|
Время выполнения в одном потоке: 2800
|
||||||
|
Время выполнения с ThreadPool: 1793455
|
||||||
|
Время выполнения с ForkJoinPool: 599719
|
||||||
|
```
|
||||||
|
|
||||||
|
### Тест 2:
|
||||||
|
**Ввод:**
|
||||||
|
```
|
||||||
|
Введите размер матрицы (от 2 до 1000): 100
|
||||||
|
```
|
||||||
|
**Вывод:**
|
||||||
|
```
|
||||||
|
Время выполнения в одном потоке: 66801
|
||||||
|
Время выполнения с ThreadPool: 5646255
|
||||||
|
Время выполнения с ForkJoinPool: 568506
|
||||||
|
```
|
||||||
|
|
||||||
|
### Тест 3:
|
||||||
|
**Ввод:**
|
||||||
|
```
|
||||||
|
Введите размер матрицы (от 2 до 1000): 1000
|
||||||
|
```
|
||||||
|
**Вывод:**
|
||||||
|
```
|
||||||
|
Время выполнения в одном потоке: 2352923
|
||||||
|
Время выполнения с ThreadPool: 14560843
|
||||||
|
Время выполнения с ForkJoinPool: 917609
|
||||||
|
```
|
||||||
|
|
||||||
|
## Вывод
|
||||||
|
|
||||||
|
В рамках лабораторной работы были реализованы и протестированы три подхода к параллельной обработке данных. ForkJoinPool показал лучшее соотношение скорости и масштабируемости при увеличении размера матрицы, особенно по сравнению с классическим ThreadPool.
|
||||||
|
|
||||||
|
Были закреплены навыки работы с потоками, параллельными вычислениями и измерением производительности различных подходов.
|
||||||
|
|
||||||
31
lyakhov_timofey_lab_1/pom.xml
Normal file
31
lyakhov_timofey_lab_1/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.urlshort</groupId>
|
||||||
|
<artifactId>sspr</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>sspr</name>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.urlshort.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
121
lyakhov_timofey_lab_1/src/main/java/org/urlshort/App.java
Normal file
121
lyakhov_timofey_lab_1/src/main/java/org/urlshort/App.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package org.urlshort;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
public class App
|
||||||
|
{
|
||||||
|
private static int[][] matrix;
|
||||||
|
private static int size;
|
||||||
|
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
|
||||||
|
do {
|
||||||
|
Scanner scanner = new java.util.Scanner(System.in);
|
||||||
|
Random random = new java.util.Random();
|
||||||
|
|
||||||
|
System.out.print("Введите размер матрицы (от 2 до 1000): ");
|
||||||
|
int size = scanner.nextInt();
|
||||||
|
|
||||||
|
if (size < 2 || size > 10000) {
|
||||||
|
System.out.println("Размер матрицы должен быть от 2 до 1000.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix = new int[size][size];
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
matrix[i][j] = random.nextInt(100) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calculateSumOfRow();
|
||||||
|
calculateSumOfRowWithThreadPool();
|
||||||
|
calculateSumOfRowWithForkPool();
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void calculateSumOfRow() {
|
||||||
|
LocalDateTime startTime = LocalDateTime.now();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
int sum = 0;
|
||||||
|
for (int[] ints : matrix) {
|
||||||
|
int product = 1;
|
||||||
|
for (int anInt : ints) {
|
||||||
|
product *= anInt;
|
||||||
|
}
|
||||||
|
sum += product;
|
||||||
|
}
|
||||||
|
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения в одном потоке: \t" + st);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void calculateSumOfRowWithThreadPool() {
|
||||||
|
int sum = 0;
|
||||||
|
int numThreads = Runtime.getRuntime().availableProcessors();
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
|
||||||
|
List<Future<Integer>> futures = new ArrayList<>();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
|
final int row = i;
|
||||||
|
futures.add(executor.submit(() -> {
|
||||||
|
int product = 1;
|
||||||
|
for (int j = 0; j < matrix[row].length; j++) {
|
||||||
|
product *= matrix[row][j];
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Future<Integer> future : futures) {
|
||||||
|
try {
|
||||||
|
sum += future.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения с ThreadPool: \t\t" + st);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void calculateSumOfRowWithForkPool(){
|
||||||
|
|
||||||
|
PartTask pt = new PartTask(matrix, 0, size + 1);
|
||||||
|
ForkJoinPool forkJoinPool = new ForkJoinPool();
|
||||||
|
long s = System.nanoTime();
|
||||||
|
forkJoinPool.invoke(pt);
|
||||||
|
long st = System.nanoTime() - s;
|
||||||
|
System.out.println("Время выполнения с ForkJoinPool: \t" + st);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
class PartTask extends RecursiveTask<Integer> {
|
||||||
|
|
||||||
|
private final int[][] matrix;
|
||||||
|
private final int start, stop;
|
||||||
|
|
||||||
|
public PartTask (int[][] matrix, int start, int stop){
|
||||||
|
this.matrix = matrix;
|
||||||
|
this.start = start;
|
||||||
|
this.stop = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer compute() {
|
||||||
|
if (start + 1 == stop){
|
||||||
|
return Arrays.stream(matrix[start]).sum();
|
||||||
|
}
|
||||||
|
PartTask p1 = new PartTask(matrix, start, (start + stop) / 2);
|
||||||
|
PartTask p2 = new PartTask(matrix, (start + stop) / 2, stop);
|
||||||
|
p1.fork();
|
||||||
|
p2.fork();
|
||||||
|
return p1.join() + p2.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user