From e3bf7794a0292ceb7ed9c39e60f54e069b656f29 Mon Sep 17 00:00:00 2001 From: "evasina2312@gmail.com" Date: Sun, 15 Dec 2024 18:04:02 +0400 Subject: [PATCH] vasina_ekaterina_lab_5_fix --- vasina_ekaterina_lab_5/README.md | 26 ++++++++++++++++ vasina_ekaterina_lab_5/app.py | 51 +++++++++++++++++++++++++++++++ vasina_ekaterina_lab_5/lab_5.png | Bin 0 -> 19610 bytes 3 files changed, 77 insertions(+) create mode 100644 vasina_ekaterina_lab_5/README.md create mode 100644 vasina_ekaterina_lab_5/app.py create mode 100644 vasina_ekaterina_lab_5/lab_5.png diff --git a/vasina_ekaterina_lab_5/README.md b/vasina_ekaterina_lab_5/README.md new file mode 100644 index 0000000..cc7b379 --- /dev/null +++ b/vasina_ekaterina_lab_5/README.md @@ -0,0 +1,26 @@ +# Лабораторная работа №5 - Параллельное умножение матриц + +## Задание + +Требуется сделать два алгоритма: обычный и параллельный. В параллельном алгоритме предусмотреть ручное задание количества потоков, каждый из которых будет выполнять умножение элементов матрицы в рамках своей зоны ответственности. + +### Описание работы программы + +Метод ```benchmark``` выполняет бенчмарк для матриц заданного размера. + +Далее генерируются две матрицы ```matrix1``` и ```matrix2``` заданного размера. + +После этого вызываются соответствующие методы для вычисления произведения матриц: ```multiply_matrices``` для обычного умножения и ```multiply_matrices_parallel``` для параллельного умножения. + +Измеряется время выполнения каждого из методов с использованием функции ```time.time()```. + +### Результат работы программы + +![](lab_5.png "") + +### Вывод + +Параллельный подход может быть более быстрым, чем последовательный на матрицах большого размера, так как он позволяет производить более Параллельное выполнение матричного умножения имеет смысл применять при работе с крупными матрицами, где выигрыш от параллельных вычислений компенсирует затраты на управление потоками. Для небольших матриц может быть эффективнее использовать обычное выполнение + +# Видеозапись работы програмы +https://vkvideo.ru/video174596752_456239398 \ No newline at end of file diff --git a/vasina_ekaterina_lab_5/app.py b/vasina_ekaterina_lab_5/app.py new file mode 100644 index 0000000..15577e2 --- /dev/null +++ b/vasina_ekaterina_lab_5/app.py @@ -0,0 +1,51 @@ +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_list=[1, 2, 4]): + # Генерация матриц + 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:.6f} секунд") + + # Бенчмарк для параллельного умножения + for num_threads in num_threads_list: + 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:.6f} секунд") + + print() + +# Запуск бенчмарков +benchmark(100) +benchmark(300) +benchmark(500) diff --git a/vasina_ekaterina_lab_5/lab_5.png b/vasina_ekaterina_lab_5/lab_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f8a98f7f34a804a69e1bb9bf5c7ecdf16eafae06 GIT binary patch literal 19610 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 literal 0 HcmV?d00001