diff --git a/antonov_dmitry_lab_5/README.md b/antonov_dmitry_lab_5/README.md new file mode 100644 index 0000000..dc87597 --- /dev/null +++ b/antonov_dmitry_lab_5/README.md @@ -0,0 +1,91 @@ +# Лабораторная работа №5 - Вспоминаем математику или параллельное перемножение матриц + +Изучение параллельного умножения матриц + +# Задачи + +Кратко: реализовать умножение двух больших квадратных матриц. + +Подробно: в лабораторной работе требуется сделать два алгоритма: обычный и параллельный +(задание со * - реализовать это в рамках одного алгоритма). В параллельном алгоритме предусмотреть +ручное задание количества потоков (число потоков = 1 как раз и реализует задание со *), каждый из +которых будет выполнять умножение элементов матрицы в рамках своей зоны ответственности. + +Сделать несколько бенчмарков последовательного и параллельного алгоритма на умножение двух матриц +размером 100x100, 300x300, 500x500 элементов. +# Запуск + +Проект запускается в ide просто по нажатию у питон файла на функцию мейн. +Нужно последовательно запустить функцию мейн у файлов simple_app.py, benchmark.py. + +# Описание работы: +Развернули два приложения + +1. Приложение 1 - веб приложение для умножения матриц +2. Приложение 2 - консольное приложение для сравнения эффективности работы алгоритмов. + +Первое приложение дает нам возможность умножить матрицы, получить результат в интерактивном режиме +с указанием используемого алгоритма и с указанием размера матрицы. +В программе предусмотрена возможность задания количества процессов для распараллеливания. +Используется библиотека python multiprocessing. + +На рис 3 видно, что с использованием параллельного алгоритма скорость обработки увеличивается довольно +существенно. Но оптимальная скорость достигается при кол-ве потоков = кол-ву потоков процессора +У меня их 16. + +

+

Форма веб приложения для указания парметров умножения матриц
+ +

+

+

Результат умножения в интерактивном режиме
+ +

+

+

Сравнение бенчмарков
+ +

+

+

Параллельное умножение в коде
+ +

+ +* Время обычное: 0.43517565727233887 с +* Размер матрицы: 100x100 +* Время обычное: 11.15409231185913 с +* Размер матрицы: 300x300 +* Время обычное: 53.64867091178894 с +* Размер матрицы: 500x500 +* Размер матрицы: 100x100 +* Время параллельное: 0.582118034362793 с +* Потоков: 2 +* Размер матрицы: 300x300 +* Время параллельное: 6.083630800247192 с +* Потоков: 2 +* Размер матрицы: 500x500 +* Время параллельное: 26.892888069152832 с +* Потоков: 2 +* Размер матрицы: 100x100 +* Время параллельное: 0.9034981727600098 с +* Потоков: 16 +* Размер матрицы: 300x300 +* Время параллельное: 2.9237937927246094 с +* Потоков: 16 +* Размер матрицы: 500x500 +* Время параллельное: 10.55041241645813 с +* Потоков: 16 +* Размер матрицы: 100x100 +* Время параллельное: 1.5674595832824707 с +* Потоков: 32 +* Размер матрицы: 300x300 +* Время параллельное: 4.185227394104004 с +* Потоков: 32 +* Размер матрицы: 500x500 +* Время параллельное: 11.912990808486938 с +* Потоков: 32 + + + +# Ссылка на видео +https://disk.yandex.ru/i/I_1oUuNTveYUdg + diff --git a/antonov_dmitry_lab_5/benchmark.py b/antonov_dmitry_lab_5/benchmark.py new file mode 100644 index 0000000..ca0a66f --- /dev/null +++ b/antonov_dmitry_lab_5/benchmark.py @@ -0,0 +1,82 @@ +import multiprocessing + +import numpy as np +import time + + +def multiply_matrices(matrix_a, matrix_b): + if len(matrix_a[0]) != len(matrix_b): + raise ValueError("матрицы имеют разную длину") + + result = [[0 for _ in range(len(matrix_b[0]))] for _ in range(len(matrix_a))] + + for i in range(len(matrix_a)): + for j in range(len(matrix_b[0])): + for k in range(len(matrix_b)): + result[i][j] += matrix_a[i][k] * matrix_b[k][j] + + return result + + +def multiply_row(args): + matrix_a, matrix_b, i = args + row_result = [0 for _ in range(len(matrix_b[0]))] + for j in range(len(matrix_b[0])): + for k in range(len(matrix_b)): + row_result[j] += matrix_a[i][k] * matrix_b[k][j] + return row_result, i + + +def multiply_matrices_parallel(matrix_a, matrix_b, threads): + if len(matrix_a[0]) != len(matrix_b): + raise ValueError("матрицы имеют разную длину") + + result = [[0 for _ in range(len(matrix_b[0]))] for _ in range(len(matrix_a))] + + with multiprocessing.Pool(processes=threads) as pool: + args_list = [(matrix_a, matrix_b, i) for i in range(len(matrix_a))] + rows_results = pool.map(multiply_row, args_list) + + for row_result, row_index in rows_results: + result[row_index] = row_result + + return result + + +def benchmark_sequential(size): + matrix_a = np.random.rand(size, size) + matrix_b = np.random.rand(size, size) + + start_time = time.time() + multiply_matrices(matrix_a, matrix_b) + end_time = time.time() + + return end_time - start_time + + +def benchmark_parallel(size, num_threads): + matrix_a = np.random.rand(size, size) + matrix_b = np.random.rand(size, size) + + start_time = time.time() + multiply_matrices_parallel(matrix_a, matrix_b, num_threads) + end_time = time.time() + + return end_time - start_time + + +if __name__ == "__main__": + sizes = [100, 300, 500] + threads = [2, 16, 32] + + for size in sizes: + sequential_time = benchmark_sequential(size) + print(f"Время обычное: {sequential_time} с") + print(f"Размер матрицы: {size}x{size}") + + for thread in threads: + for size in sizes: + parallel_time = benchmark_parallel(size, thread) + print(f"Размер матрицы: {size}x{size}") + print(f"Время параллельное: {parallel_time} с") + print(f"Потоков: {thread}") diff --git a/antonov_dmitry_lab_5/screens/img.png b/antonov_dmitry_lab_5/screens/img.png new file mode 100644 index 0000000..ba5b28a Binary files /dev/null and b/antonov_dmitry_lab_5/screens/img.png differ diff --git a/antonov_dmitry_lab_5/screens/img_1.png b/antonov_dmitry_lab_5/screens/img_1.png new file mode 100644 index 0000000..72e917f Binary files /dev/null and b/antonov_dmitry_lab_5/screens/img_1.png differ diff --git a/antonov_dmitry_lab_5/screens/img_2.png b/antonov_dmitry_lab_5/screens/img_2.png new file mode 100644 index 0000000..24fb785 Binary files /dev/null and b/antonov_dmitry_lab_5/screens/img_2.png differ diff --git a/antonov_dmitry_lab_5/screens/img_3.png b/antonov_dmitry_lab_5/screens/img_3.png new file mode 100644 index 0000000..9f58aba Binary files /dev/null and b/antonov_dmitry_lab_5/screens/img_3.png differ diff --git a/antonov_dmitry_lab_5/simple_app.py b/antonov_dmitry_lab_5/simple_app.py new file mode 100644 index 0000000..740bcda --- /dev/null +++ b/antonov_dmitry_lab_5/simple_app.py @@ -0,0 +1,73 @@ +import multiprocessing + +from flask import Flask, render_template, request +import numpy as np +import concurrent.futures + +app = Flask(__name__) + + +def multiply_matrices(matrix_a, matrix_b): + if len(matrix_a[0]) != len(matrix_b): + raise ValueError("матрицы имеют разную длину") + + result = [[0 for _ in range(len(matrix_b[0]))] for _ in range(len(matrix_a))] + + for i in range(len(matrix_a)): + for j in range(len(matrix_b[0])): + for k in range(len(matrix_b)): + result[i][j] += matrix_a[i][k] * matrix_b[k][j] + + return result + + +def multiply_row(args): + matrix_a, matrix_b, i = args + row_result = [0 for _ in range(len(matrix_b[0]))] + for j in range(len(matrix_b[0])): + for k in range(len(matrix_b)): + row_result[j] += matrix_a[i][k] * matrix_b[k][j] + return row_result, i + + +def multiply_matrices_parallel(matrix_a, matrix_b, threads): + if len(matrix_a[0]) != len(matrix_b): + raise ValueError("матрицы имеют разную длину") + + result = [[0 for _ in range(len(matrix_b[0]))] for _ in range(len(matrix_a))] + + with multiprocessing.Pool(processes=threads) as pool: + args_list = [(matrix_a, matrix_b, i) for i in range(len(matrix_a))] + rows_results = pool.map(multiply_row, args_list) + + for row_result, row_index in rows_results: + result[row_index] = row_result + + return result + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/multiply', methods=['POST']) +def multiply(): + n = int(request.form.get('matrix_a')) + matrix_a = np.random.randint(10, size=(n, n)) + matrix_b = np.random.randint(10, size=(n, n)) + + operation_type = request.form.get('operation_type') + + if operation_type == 'sequential': + result = multiply_matrices(matrix_a, matrix_b) + elif operation_type == 'parallel': + result = multiply_matrices_parallel(matrix_a, matrix_b, 16) + else: + return "Invalid operation type" + + return render_template('result.html', matrix_a=matrix_a, matrix_b=matrix_b, result=result) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/antonov_dmitry_lab_5/templates/index.html b/antonov_dmitry_lab_5/templates/index.html new file mode 100644 index 0000000..c08fa5e --- /dev/null +++ b/antonov_dmitry_lab_5/templates/index.html @@ -0,0 +1,24 @@ + + + + + + + Умножение матриц + + +

Умножение матриц

+
+ +
+ + +
+ + +
+ + diff --git a/antonov_dmitry_lab_5/templates/result.html b/antonov_dmitry_lab_5/templates/result.html new file mode 100644 index 0000000..23bdc89 --- /dev/null +++ b/antonov_dmitry_lab_5/templates/result.html @@ -0,0 +1,19 @@ + + + + + + + Результат + + +

Результат

+

Матрица A:

+
{{ matrix_a }}
+

Матрица B:

+
{{ matrix_b }}
+

Результат:

+
{{ result }}
+ Назад + +