diff --git a/vaksman_valeria_lab_5/1.png b/vaksman_valeria_lab_5/1.png new file mode 100644 index 0000000..eb24b2f Binary files /dev/null and b/vaksman_valeria_lab_5/1.png differ diff --git a/vaksman_valeria_lab_5/README.md b/vaksman_valeria_lab_5/README.md new file mode 100644 index 0000000..9b34867 --- /dev/null +++ b/vaksman_valeria_lab_5/README.md @@ -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 \ No newline at end of file diff --git a/vaksman_valeria_lab_5/docker-compose.yml b/vaksman_valeria_lab_5/docker-compose.yml new file mode 100644 index 0000000..15851d1 --- /dev/null +++ b/vaksman_valeria_lab_5/docker-compose.yml @@ -0,0 +1,9 @@ +services: + + project: + container_name: project + build: + context: . + dockerfile: ./project/Dockerfile + expose: + - 8008 diff --git a/vaksman_valeria_lab_5/project/Dockerfile b/vaksman_valeria_lab_5/project/Dockerfile new file mode 100644 index 0000000..9fd699f --- /dev/null +++ b/vaksman_valeria_lab_5/project/Dockerfile @@ -0,0 +1,11 @@ +# Использую базовый образ Python +FROM python:3.10-slim + +# Устанавливаю рабочую директорию внутри контейнера +WORKDIR /app + +# Копирую исполняемый файл +COPY project/main.py . + +# Команда для запуска Python-скрипта +CMD ["python", "main.py"] \ No newline at end of file diff --git a/vaksman_valeria_lab_5/project/main.py b/vaksman_valeria_lab_5/project/main.py new file mode 100644 index 0000000..8be579e --- /dev/null +++ b/vaksman_valeria_lab_5/project/main.py @@ -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() \ No newline at end of file