diff --git a/alexandrov_dmitrii_lab_5/matrix.py b/alexandrov_dmitrii_lab_5/matrix.py
new file mode 100644
index 0000000..71a1468
--- /dev/null
+++ b/alexandrov_dmitrii_lab_5/matrix.py
@@ -0,0 +1,109 @@
+import numpy as np
+import time
+from concurrent.futures import ProcessPoolExecutor
+
+benchmark = {}
+m_a = []
+m_b = []
+m_c = []
+
+
+# лучше не надо
+def do_multiplication(size):
+ global m_a
+ global m_b
+ global m_c
+
+ m_a = np.random.randint(10, size=(size, size))
+ m_b = np.random.randint(10, size=(size, size))
+ m_c = np.zeros(shape=(size, size))
+ bt = m_b.transpose()
+
+ start_time = time.time()
+ for i in range(size):
+ for j in range(size):
+ for k in range(size):
+ m_c[i][j] = m_c[i][j] + m_a[i][k] * bt[j][k]
+
+ return time.time() - start_time
+
+
+def multiply_row(a, bt, c, size):
+ for j in range(size):
+ c[j] = sum(el_a * el_b for el_a, el_b in zip(a, bt[j]))
+ return c
+
+
+def do_multiplication_parallel(size, proc_num):
+ global m_a
+ global m_b
+ global m_c
+
+ if proc_num > 61:
+ proc_num = 61
+
+ m_a = np.random.randint(10, size=(size, size))
+ m_b = np.random.randint(10, size=(size, size))
+ m_c = np.zeros(shape=(size, size))
+ bt = m_b.transpose()
+
+ start_time = time.time()
+ with ProcessPoolExecutor(max_workers=proc_num) as executor:
+ results = [executor.submit(multiply_row, m_a[i], bt, m_c[i], size) for i in range(size)]
+ m_c = [future.result() for future in results]
+
+ return time.time() - start_time
+
+
+def do_research():
+ benchmark['size=100, proc_num=1: '] = do_multiplication_parallel(100, 1)
+ benchmark['size=300, proc_num=1: '] = do_multiplication_parallel(300, 1)
+ benchmark['size=500, proc_num=1: '] = do_multiplication_parallel(500, 1)
+ benchmark['size=100, proc_num=10: '] = do_multiplication_parallel(100, 10)
+ benchmark['size=300, proc_num=10: '] = do_multiplication_parallel(300, 10)
+ benchmark['size=500, proc_num=10: '] = do_multiplication_parallel(500, 10)
+ benchmark['size=100, proc_num=100: '] = do_multiplication_parallel(100, 100)
+ benchmark['size=300, proc_num=100: '] = do_multiplication_parallel(300, 100)
+ benchmark['size=500, proc_num=100: '] = do_multiplication_parallel(500, 100)
+ print(benchmark)
+
+
+if __name__ == '__main__':
+ do_research()
+
+
+def get_results(size, proc_num):
+ global m_a
+ global m_b
+ global m_c
+
+ res = "time: "
+ res = res + str(do_multiplication_parallel(size, proc_num))
+
+ res = res + "
"
+ for i in range(size):
+ res = res + "
" + for a in range(size): + res = res + str(m_a[i][a]) + ", " + res = res + " " + for b in range(size): + res = res + str(m_b[i][b]) + ", " + res = res + " " + for c in range(size): + res = res + str(m_c[i][c]) + ", " + res = res + "
" + + return res + + +def get_benchmark(): + global benchmark + + if len(benchmark) == 0: + do_research() + + res = '' + for key, val in benchmark.items(): + res = res + "" + key + str(val) + "
" + + return res diff --git a/alexandrov_dmitrii_lab_5/readme.md b/alexandrov_dmitrii_lab_5/readme.md new file mode 100644 index 0000000..b89568c --- /dev/null +++ b/alexandrov_dmitrii_lab_5/readme.md @@ -0,0 +1,37 @@ +## Задание +Создать программу, производящую параллельные умножения реализовать двух больших квадратных матриц. + +## Выполнение +Программа состоит из модуля-сервиса service и модуля для вычислений matrix. +В модуле для вычислений реализовано: +* метод do_multiplication, который в обычном режиме одним потоком умножает матрицы. Не используется, т.к. слишком медленный. +* метод multiply_row, который получает строку матрицы A, транспонированную матрицу B, строку выходной матрицы C, размер матриц и заполняет эту строку проходя по строкам транспонированной матрицы B. Возвращает заполненную строку. +* метод do_multiplication_parallel, использующий предыдущий, который получает размер матриц и количество процессов, генерирует случайные матрицы заданного размера и производит вычисления. +* метод прогона эксперимента с заполнением данных результатами. Методы интерфейса доступа. + +Способ вычисления: в методе do_multiplication_parallel матрица B транспонируется, создаётся объект ProcessPoolExecutor с переданным количеством процессов, который их создаёт и распределяет по ним строки вычисляемой матрицы, а именно передавая им метод multiply_row. +Если передать методу число 1 в качестве количества процессов, то соответственно вычисление произойдёт в одном потоке. + +## Результаты +Был создан Flask сервис, позволяющий получать результаты умножения случайных квадратных матриц. +Возможно задать размер и количество процессов. + +Дополнительно возможно провести эксперимент и получить результаты умножения матриц размера 100, 300 и 500 одним, десятью и ста процессами. + +Поскольку распараллеливание основано на процессах, а в системе имеется 6 ядер (+2 виртуальных), то максимальное увеличение производительности будет достигнуто при выборе такого количества процессов. +Более 61 потока урезается до 61 из-за системных ограничений. +Как видно из бенчмарка: +* во всех случаях скорость максимальна при выборе 10 процессов, т.е. при ближайшем к 8 числу процессов. +* в случае 100 процессов из-за издержек создания процессов малые матрицы обрабатываются на порядок дольше, нежели одним процессом. +* в случае 100 процессов благодаря распараллеливанию скорость обработки оказалась в 3 раза выше скорости обработки одним процессом. + +Результаты: +![matrix5x5](screens/get5.png) + +![matrix15x15](screens/get15.png) + +Бенчмарк: +![bench](screens/bench.png) + +## Ссылка на видео +https://drive.google.com/file/d/1_bIyLL8YGwDePwWdCFk4KxntJip6mP0t/view?usp=drive_link \ No newline at end of file diff --git a/alexandrov_dmitrii_lab_5/screens/bench.png b/alexandrov_dmitrii_lab_5/screens/bench.png new file mode 100644 index 0000000..2ffefcf Binary files /dev/null and b/alexandrov_dmitrii_lab_5/screens/bench.png differ diff --git a/alexandrov_dmitrii_lab_5/screens/get15.png b/alexandrov_dmitrii_lab_5/screens/get15.png new file mode 100644 index 0000000..4d25d26 Binary files /dev/null and b/alexandrov_dmitrii_lab_5/screens/get15.png differ diff --git a/alexandrov_dmitrii_lab_5/screens/get5.png b/alexandrov_dmitrii_lab_5/screens/get5.png new file mode 100644 index 0000000..022b4b5 Binary files /dev/null and b/alexandrov_dmitrii_lab_5/screens/get5.png differ diff --git a/alexandrov_dmitrii_lab_5/service.py b/alexandrov_dmitrii_lab_5/service.py new file mode 100644 index 0000000..3b1f5bd --- /dev/null +++ b/alexandrov_dmitrii_lab_5/service.py @@ -0,0 +1,35 @@ +from flask import Flask, redirect, request, render_template +import matrix + +app = Flask(__name__, template_folder='') + +results = '' + + +@app.route('/') +def home(): + global results + return render_template("template.html", results_html=results) + + +@app.route('/do') +def do(): + global results + + data = request.args + results = matrix.get_results(int(data['size']), int(data['proc_num'])) + + return redirect("/") + + +@app.route('/benchmark') +def benchmark(): + global results + + results = matrix.get_benchmark() + + return redirect("/") + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=8082) diff --git a/alexandrov_dmitrii_lab_5/template.html b/alexandrov_dmitrii_lab_5/template.html new file mode 100644 index 0000000..c999367 --- /dev/null +++ b/alexandrov_dmitrii_lab_5/template.html @@ -0,0 +1,18 @@ + + + + +