alexandrov_dmitrii_lab_5 lab 5 is ready #71
109
alexandrov_dmitrii_lab_5/matrix.py
Normal file
109
alexandrov_dmitrii_lab_5/matrix.py
Normal 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 + " "
|
||||||
|
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 + "</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
|
37
alexandrov_dmitrii_lab_5/readme.md
Normal file
37
alexandrov_dmitrii_lab_5/readme.md
Normal file
@ -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
|
BIN
alexandrov_dmitrii_lab_5/screens/bench.png
Normal file
BIN
alexandrov_dmitrii_lab_5/screens/bench.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
BIN
alexandrov_dmitrii_lab_5/screens/get15.png
Normal file
BIN
alexandrov_dmitrii_lab_5/screens/get15.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
BIN
alexandrov_dmitrii_lab_5/screens/get5.png
Normal file
BIN
alexandrov_dmitrii_lab_5/screens/get5.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
35
alexandrov_dmitrii_lab_5/service.py
Normal file
35
alexandrov_dmitrii_lab_5/service.py
Normal 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)
|
18
alexandrov_dmitrii_lab_5/template.html
Normal file
18
alexandrov_dmitrii_lab_5/template.html
Normal 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="proc_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>
|
Loading…
Reference in New Issue
Block a user