From fa1bb4692ad860c080f33742351f8550bd06d318 Mon Sep 17 00:00:00 2001 From: enuementtt Date: Tue, 16 Jan 2024 18:15:06 +0400 Subject: [PATCH] romanova_adelina_lab_5_ready --- romanova_adelina_lab_5/README.md | 33 ++++++++++++++++++++ romanova_adelina_lab_5/main.py | 48 ++++++++++++++++++++++++++++++ romanova_adelina_lab_5/result.png | Bin 0 -> 21349 bytes 3 files changed, 81 insertions(+) create mode 100644 romanova_adelina_lab_5/README.md create mode 100644 romanova_adelina_lab_5/main.py create mode 100644 romanova_adelina_lab_5/result.png diff --git a/romanova_adelina_lab_5/README.md b/romanova_adelina_lab_5/README.md new file mode 100644 index 0000000..6368931 --- /dev/null +++ b/romanova_adelina_lab_5/README.md @@ -0,0 +1,33 @@ +# Лабораторная работа 5. Параллельное умножение матриц + +## Задание + +Требуется сделать два алгоритма: обычный и параллельный. В параллельном алгоритме предусмотреть ручное задание количества потоков, каждый из которых будет выполнять умножение элементов матрицы в рамках своей зоны ответственности. + +### Запуск программы + +Для запуска программы необходимо с помощью командной строки в корневой директории файлов прокета прописать: +``` +python main.py +``` + +### Описание работы программы + +Метод ```benchmark``` выполняет бенчмарк для матриц заданного размера. + +Далее генерируются две матрицы ```matrix1``` и ```matrix2``` заданного размера. + +После этого вызываются соответствующие методы для вычисления произведения матриц: ```multiply_matrices``` для обычного умножения и ```multiply_matrices_parallel``` для параллельного умножения. + +Измеряется время выполнения каждого из методов с использованием функции ```time.time()```. + +### Результат работы программы: + +![](result.png "") + +#### Вывод + +Параллельное выполнение матричного умножения имеет смысл применять при работе с крупными матрицами, где выигрыш от параллельных вычислений компенсирует затраты на управление потоками. Для небольших матриц может быть эффективнее использовать обычное выполнение + +# Youtube +https://youtu.be/kX6FrGL9DP0 \ No newline at end of file diff --git a/romanova_adelina_lab_5/main.py b/romanova_adelina_lab_5/main.py new file mode 100644 index 0000000..e621c71 --- /dev/null +++ b/romanova_adelina_lab_5/main.py @@ -0,0 +1,48 @@ +import numpy as np +import time +import concurrent.futures + +def multiply_matrices(matrix1, matrix2): + return np.dot(matrix1, matrix2) + +def multiply_matrices_parallel(matrix1, matrix2, num_threads): + result = np.zeros_like(matrix1) + chunk_size = matrix1.shape[0] // num_threads + + def multiply_chunk(start, end): + nonlocal result + for i in range(start, end): + result[i] = np.dot(matrix1[i], matrix2) + + with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor: + futures = [] + for i in range(0, matrix1.shape[0], chunk_size): + futures.append(executor.submit(multiply_chunk, i, i + chunk_size)) + + for future in concurrent.futures.as_completed(futures): + future.result() + + return result + +def benchmark(matrix_size, num_threads=1): + # Генерация матриц + matrix1 = np.random.rand(matrix_size, matrix_size) + matrix2 = np.random.rand(matrix_size, matrix_size) + + # Бенчмарк для обычного умножения + start_time = time.time() + result = multiply_matrices(matrix1, matrix2) + end_time = time.time() + print(f"Размер матрицы {matrix_size}x{matrix_size}") + print(f"Время при обычном выполнении: {end_time - start_time} секунд") + + # Бенчмарк для параллельного умножения + start_time = time.time() + result_parallel = multiply_matrices_parallel(matrix1, matrix2, num_threads) + end_time = time.time() + print(f"Время при параллельном выполнении ({num_threads} потоков): {end_time - start_time} секунд\n") + +# Запуск бенчмарков +benchmark(100) +benchmark(300) +benchmark(500) diff --git a/romanova_adelina_lab_5/result.png b/romanova_adelina_lab_5/result.png new file mode 100644 index 0000000000000000000000000000000000000000..938e8a160701ebb49286b99af1bc61e44e138181 GIT binary patch literal 21349 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≶5NZs@G=^UN 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 Pfij<`tDnm{r-UW|crGFd literal 0 HcmV?d00001