alexandrov_dmitrii_lab_5 lab 5 is ready #71

Merged
Alexey merged 6 commits from alexandrov_dmitrii_lab_5 into main 2023-12-28 11:00:22 +04:00
7 changed files with 193 additions and 0 deletions
Showing only changes of commit 06de5e8246 - Show all commits

View File

@ -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 + "<br/>"
for i in range(size):
res = res + "<p>"
for a in range(size):
res = res + str(m_a[i][a]) + ", "
res = res + "&emsp;"
for b in range(size):
res = res + str(m_b[i][b]) + ", "
res = res + "&emsp;"
for c in range(size):
res = res + str(m_c[i][c]) + ", "
res = res + "</p>"
return res
def get_benchmark():
global benchmark
if len(benchmark) == 0:
do_research()
res = ''
for key, val in benchmark.items():
res = res + "<p>" + key + str(val) + "</p>"
return res

View File

@ -0,0 +1,31 @@
## Задание
Создать программу, производящую параллельные умножения реализовать двух больших квадратных матриц.
## Выполнение
Программа состоит из модуля-сервиса service и модуля для вычислений matrix.
В модуле для вычислений реализовано:
* метод do_multiplication, который в обычном режиме одним потоком умножает матрицы. Не используется, т.к. слишком медленный.
* метод multiply_row, который получает строку матрицы A, транспонированную матрицу B, строку выходной матрицы C, размер матриц и заполняет эту строку проходя по строкам транспонированной матрицы B. Возвращает заполненную строку.
* метод do_multiplication_parallel, использующий предыдущий, который получает размер матриц и количество процессов, генерирует случайные матрицы заданного размера и производит вычисления.
* метод прогона эксперимента с заполнением данных результатами. Методы интерфейса доступа.
Способ вычисления: в методе do_multiplication_parallel матрица B транспонируется, создаётся объект ThreadPoolExecutor с переданным количеством потоков, который их создаёт и распределяет по ним строки вычисляемой матрицы, а именно передавая им метод multiply_row.
Если передать методу число 1 в качестве количества потоков, то соответственно вычисление произойдёт в одном потоке.
## Результаты
Был создан Flask сервис, позволяющий получать результаты умножения случайных квадратных матриц.
Возможно задать размер и количество потоков.
Дополнительно возможно провести эксперимент и получить результаты умножения матриц размера 100, 300 и 500 одним, десятью и ста потоками.
Поскольку распараллеливание основано на процессах, а в системе имеется 6 ядер, то максимальное увеличение производительности будет достигнуто при выборе такого количества процессов.
Результаты:
![RabbitMQ](screens/get5.png)
![MediaWiki](screens/get15.png)
Бенчмарк:
![MediaWiki](screens/bench.png)
## Ссылка на видео

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -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)

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Matrix</title>
</head>
<body>
<form action="http://127.0.0.1:8082/do">
<input type="number" id="size" name="size" value="5">
<input type="number" id="thread_num" name="proc_num" value="1">
<input align="center" type="submit" value="Выполнить"/>
</form>
<form action="http://127.0.0.1:8082/benchmark">
<input align="center" type="submit" value="Вывести бенчмарк"/>
</form>
{{results_html|safe}}
</body>
</html>