From 26fed4644379596cc62d624ef821b87ff81dcb36 Mon Sep 17 00:00:00 2001 From: Tyurner Date: Sun, 10 Nov 2024 13:52:54 +0400 Subject: [PATCH] turner_ilya_lab_5 is ready --- turner_ilya_lab_5/README.md | 18 +++++++++++ turner_ilya_lab_5/main.py | 58 ++++++++++++++++++++++++++++++++++ turner_ilya_lab_5/results.png | Bin 0 -> 13323 bytes 3 files changed, 76 insertions(+) create mode 100644 turner_ilya_lab_5/README.md create mode 100644 turner_ilya_lab_5/main.py create mode 100644 turner_ilya_lab_5/results.png diff --git a/turner_ilya_lab_5/README.md b/turner_ilya_lab_5/README.md new file mode 100644 index 0000000..b090232 --- /dev/null +++ b/turner_ilya_lab_5/README.md @@ -0,0 +1,18 @@ +# Лабораторная работа №5 - Параллельное перемножение матриц +## ПИбд-42 || Тюрнер Илья + +### Цель лабораторной работы +Изучение принципов работы праллельных вычислений, когда они оправданы, а когда нет. + +### Описание: +Был реализован механизм параллельного перемножения матриц 100x100, 300x300 и 500x500 с возможностью задания потоков, в том числе и 1 (последовательное перемножение). Были сделаны замеры времени для каждого вычисления, проведен анализ и сделаны выводы. + +### Результаты: +![Изображение 1](./results.png) + +### Выводы: +При параллельном перемножении матриц мы стремимся снизить временные затраты за счет увеличения числа потоков, на крупных матрицах это действительно дает ощутимый эффект. Однако, такое выполнение оправдано только тогда, когда затраты организацию многопоточности не превышают выигрыш от такой работы, т. е. для мелких задач такой подход не стоит применять, что можно заметить по перемножению матриц 100x100, там выигрыша практически нет. Также в определенный момент увеличение числа потоков в принципе перестает давать выигрыш. В таком случае оптимальное количество потоков было определено. + +### Видео с демонстрацией работы: +Размещено на платформе VK видео +https://vk.com/video/@tyurner02?z=video303312410_456239081%2Fpl_303312410_-2 \ No newline at end of file diff --git a/turner_ilya_lab_5/main.py b/turner_ilya_lab_5/main.py new file mode 100644 index 0000000..2172c2f --- /dev/null +++ b/turner_ilya_lab_5/main.py @@ -0,0 +1,58 @@ +import random +import time +import multiprocessing +import numpy as np + +# Генерация матрицы +def generate_matrix(size): + return [[random.randint(0, 10) for _ in range(size)] for _ in range(size)] + +# Умножение одной строки +def multiply_row(i, A, B, result): + size = len(A) + for j in range(size): + for k in range(size): + result[i][j] += A[i][k] * B[k][j] + +# параллельное умножение матриц с помощью multiprocessing +def parallel_matrix_multiply(A, B, num_processes): + size = len(A) + result = [[0] * size for _ in range(size)] + + with multiprocessing.Pool(processes=num_processes) as pool: + pool.starmap(multiply_row, [(i, A, B, result) for i in range(size)]) + + return result + +# Замер времени на умножение +def benchmark(size, num_processes=1): + A = generate_matrix(size) + B = generate_matrix(size) + + start_time = time.time() + parallel_matrix_multiply(A, B, num_processes) + par_time = time.time() - start_time + + return par_time + +def main(): + # Размеры матриц + matrix_sizes = [100, 300, 500] + # Количество потоков + num_processes_list = [1, 2, 4, 6, 8] + # Таблица с бенчмарками + print("-*" * 40) + print(f"{'Количество потоков':<20}{'|100x100 (сек.)':<20}{'|300x300 (сек.)':<20}{'|500x500 (сек.)'}") + print("-*" * 40) + + for num_processes in num_processes_list: + row = f"{num_processes:<20}" + + for size in matrix_sizes: + par_time = benchmark(size, num_processes) + row += f"|{par_time:.4f}".ljust(20) + print(row) + print("-*" * 40) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/turner_ilya_lab_5/results.png b/turner_ilya_lab_5/results.png new file mode 100644 index 0000000000000000000000000000000000000000..26d250d229f0b4819d959e776d34745453b81dae GIT binary patch literal 13323 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 scg0hh^cNYNBp3cb=USHK5|N7hi0jGV(P5=M^ literal 0 HcmV?d00001