forked from Alexey/DAS_2024_1
Merge pull request 'vaksman_valeria_lab_5' (#70) from vaksman_valeria_lab_5 into main
Reviewed-on: Alexey/DAS_2024_1#70
This commit is contained in:
commit
63e031ef17
BIN
vaksman_valeria_lab_5/1.png
Normal file
BIN
vaksman_valeria_lab_5/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
31
vaksman_valeria_lab_5/README.md
Normal file
31
vaksman_valeria_lab_5/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Лабораторная работа 5. Параллельное умножение матриц
|
||||||
|
|
||||||
|
## Задание
|
||||||
|
|
||||||
|
Требуется сделать два алгоритма: обычный и параллельный. В параллельном алгоритме предусмотреть ручное задание количества потоков, каждый из которых будет выполнять умножение элементов матрицы в рамках своей зоны ответственности.
|
||||||
|
|
||||||
|
### Запуск программы
|
||||||
|
|
||||||
|
Для запуска программы необходимо с помощью командной строки в корневой директории файлов прокета прописать:
|
||||||
|
```
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Описание работы программы
|
||||||
|
|
||||||
|
Генерируются две матрицы ```first_matrix``` и ```second_matrix``` заданного размера.
|
||||||
|
|
||||||
|
После этого вызываются соответствующие методы для вычисления произведения матриц: ```matrix_multiplication``` - простая функция перемножения матриц и ```matrix_multiplication_treads``` - функция перемножения матриц в потоке.
|
||||||
|
|
||||||
|
Измеряется время выполнения каждого из методов с использованием функции ```time.time()```.
|
||||||
|
|
||||||
|
### Результат работы программы:
|
||||||
|
|
||||||
|
![](1.png "")
|
||||||
|
|
||||||
|
#### Вывод
|
||||||
|
|
||||||
|
Параллельное выполнение матричного умножения имеет смысл применять при работе с крупными матрицами, где выигрыш от параллельных вычислений компенсирует затраты на управление потоками. Для небольших матриц может быть эффективнее использовать обычное выполнение
|
||||||
|
|
||||||
|
# ВК
|
||||||
|
https://vk.com/video256017065_456239875
|
9
vaksman_valeria_lab_5/docker-compose.yml
Normal file
9
vaksman_valeria_lab_5/docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
|
||||||
|
project:
|
||||||
|
container_name: project
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./project/Dockerfile
|
||||||
|
expose:
|
||||||
|
- 8008
|
11
vaksman_valeria_lab_5/project/Dockerfile
Normal file
11
vaksman_valeria_lab_5/project/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Использую базовый образ Python
|
||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
# Устанавливаю рабочую директорию внутри контейнера
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Копирую исполняемый файл
|
||||||
|
COPY project/main.py .
|
||||||
|
|
||||||
|
# Команда для запуска Python-скрипта
|
||||||
|
CMD ["python", "main.py"]
|
201
vaksman_valeria_lab_5/project/main.py
Normal file
201
vaksman_valeria_lab_5/project/main.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import random
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import copy
|
||||||
|
from multiprocessing import Pool
|
||||||
|
|
||||||
|
|
||||||
|
class Matrix:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.matrix_100 = [[0] * 100 for _ in range(100)]
|
||||||
|
self.matrix_300 = [[0] * 300 for _ in range(300)]
|
||||||
|
self.matrix_500 = [[0] * 500 for _ in range(500)]
|
||||||
|
|
||||||
|
def str_matrix(self, type_list: str):
|
||||||
|
_str = ""
|
||||||
|
|
||||||
|
current_matrix = getattr(self, type_list)
|
||||||
|
|
||||||
|
for i in range(len(current_matrix)):
|
||||||
|
_str += "[ "
|
||||||
|
|
||||||
|
for j in range(len(current_matrix[0])):
|
||||||
|
_str += str(current_matrix[i][j]) + " "
|
||||||
|
|
||||||
|
_str += " ]\n"
|
||||||
|
|
||||||
|
return _str
|
||||||
|
|
||||||
|
# Глобальный объект класса для хранения результата работы потоков
|
||||||
|
result_matrix = copy.deepcopy(Matrix())
|
||||||
|
|
||||||
|
def init_matrix(matrix: Matrix, size: int):
|
||||||
|
support_list_main = []
|
||||||
|
|
||||||
|
for i in range(size):
|
||||||
|
support_list_column = []
|
||||||
|
|
||||||
|
for j in range(size):
|
||||||
|
support_list_column.append(random.randint(0, 10))
|
||||||
|
|
||||||
|
support_list_main.append(support_list_column)
|
||||||
|
|
||||||
|
if size == 100:
|
||||||
|
matrix.matrix_100 = support_list_main
|
||||||
|
elif size == 300:
|
||||||
|
matrix.matrix_300 = support_list_main
|
||||||
|
elif size == 500:
|
||||||
|
matrix.matrix_500 = support_list_main
|
||||||
|
|
||||||
|
|
||||||
|
# Простая функция перемножения матриц
|
||||||
|
def matrix_multiplication(matrix_first: Matrix, matrix_second: Matrix, type_matrix: str):
|
||||||
|
result_matrix = Matrix()
|
||||||
|
|
||||||
|
first_matrix = getattr(matrix_first, type_matrix)
|
||||||
|
second_matrix = getattr(matrix_second, type_matrix)
|
||||||
|
result = getattr(result_matrix, type_matrix)
|
||||||
|
|
||||||
|
for i in range(len(first_matrix)):
|
||||||
|
for j in range(len(second_matrix[0])):
|
||||||
|
for k in range(len(second_matrix)):
|
||||||
|
result[i][j] += first_matrix[i][k] * second_matrix[k][j]
|
||||||
|
|
||||||
|
return result_matrix
|
||||||
|
|
||||||
|
|
||||||
|
# Функция перемножения матриц в потоке
|
||||||
|
def matrix_multiplication_worker(args):
|
||||||
|
first_matrix, second_matrix, type_matrix, support_index, number_thread = args
|
||||||
|
global result_matrix
|
||||||
|
|
||||||
|
result = getattr(result_matrix, type_matrix)
|
||||||
|
|
||||||
|
for i in range(support_index[0], support_index[1]):
|
||||||
|
for j in range(len(second_matrix[0])):
|
||||||
|
for k in range(len(second_matrix)):
|
||||||
|
result[i][j] += first_matrix[i - support_index[0]][k] * second_matrix[k][j]
|
||||||
|
|
||||||
|
return f"Worker completed task of {number_thread}"
|
||||||
|
|
||||||
|
def matrix_multiplication_treads(matrix_first: Matrix, matrix_second: Matrix, type_matrix: str, count_thread: int):
|
||||||
|
first_matrix = getattr(matrix_first, type_matrix)
|
||||||
|
second_matrix = getattr(matrix_second, type_matrix)
|
||||||
|
|
||||||
|
# кол-во строк с конца
|
||||||
|
last_row = 0
|
||||||
|
|
||||||
|
if len(first_matrix) % count_thread == 0:
|
||||||
|
index_rows_by_thread = len(first_matrix) // count_thread
|
||||||
|
else:
|
||||||
|
index_rows_by_thread = len(first_matrix) // count_thread
|
||||||
|
last_row = len(first_matrix) % count_thread
|
||||||
|
|
||||||
|
# "распиливаем" первую матрицу на кол-во потоков. Результатом работы каждого потока будет являться часть перемноженной матрицы
|
||||||
|
support_matrix = []
|
||||||
|
|
||||||
|
for i in range(count_thread):
|
||||||
|
start_index = i * index_rows_by_thread
|
||||||
|
|
||||||
|
if i == count_thread - 1 and last_row > 0:
|
||||||
|
end_index = start_index + last_row
|
||||||
|
else:
|
||||||
|
end_index = start_index + index_rows_by_thread
|
||||||
|
|
||||||
|
support_matrix.append((first_matrix[start_index:end_index], second_matrix, type_matrix, [start_index, end_index], i))
|
||||||
|
|
||||||
|
|
||||||
|
# Попытка запуска нескольких ПОТОКОВ. Gil не дал получить выйгрыш, так как из-за его особенностей не давал параллельно вычислить перемножение двух матриц
|
||||||
|
# формируем пул потоков
|
||||||
|
# workers = [threading.Thread(target=matrix_multiplication_worker, args=(support_matrix[f], second_matrix, type_matrix, support_matrix_index[f], f), daemon=True) for f in range(count_thread)]
|
||||||
|
|
||||||
|
# for worker in workers:
|
||||||
|
# worker.start()
|
||||||
|
|
||||||
|
# for worker in workers:
|
||||||
|
# worker.join()
|
||||||
|
|
||||||
|
# Создание пула процессов и запуск параллельного выполнения
|
||||||
|
with Pool(processes=count_thread) as pool:
|
||||||
|
pool.map(matrix_multiplication_worker, support_matrix)
|
||||||
|
|
||||||
|
return "Done."
|
||||||
|
|
||||||
|
def run_program():
|
||||||
|
matrix_first = Matrix()
|
||||||
|
init_matrix(matrix_first, 100)
|
||||||
|
init_matrix(matrix_first, 300)
|
||||||
|
init_matrix(matrix_first, 500)
|
||||||
|
|
||||||
|
matrix_second = Matrix()
|
||||||
|
init_matrix(matrix_second, 100)
|
||||||
|
init_matrix(matrix_second, 300)
|
||||||
|
init_matrix(matrix_second, 500)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication(matrix_first, matrix_second, "matrix_100")
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 100x100: ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_100", 3)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 100x100, 3 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_100", 5)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 100x100, 5 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_100", 8)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 100x100, 8 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------------
|
||||||
|
print("\n" + "-" * 50 + "\n")
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication(matrix_first, matrix_second, "matrix_300")
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 300x300: ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_300", 3)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 300x300, 3 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_300", 5)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 300x300, 5 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_300", 8)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 300x300, 8 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------------
|
||||||
|
print("\n" + "-" * 50 + "\n")
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication(matrix_first, matrix_second, "matrix_500")
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 500x500: ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_500", 3)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 500x500, 3 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_500", 5)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 500x500, 5 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
matrix_multiplication_treads(matrix_first, matrix_second, "matrix_500", 8)
|
||||||
|
end_time = time.time()
|
||||||
|
print("Time 500x500, 8 threads (processes): ", end_time - start_time)
|
||||||
|
|
||||||
|
run_program()
|
Loading…
Reference in New Issue
Block a user