Merge pull request 'pupkov_alexey_lab_5' (#197) from pupkov_alexey_lab_5 into main
Reviewed-on: #197
This commit is contained in:
commit
6ea7581574
70
pupkov_alexey_lab_5/README.md
Normal file
70
pupkov_alexey_lab_5/README.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Пупков Алексей ИСЭбд-41
|
||||||
|
# Отчет по умножению матриц
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
В данной лабораторной работе реализованы два алгоритма для умножения больших квадратных матриц: последовательный и параллельный. Для параллельного вычисления используется библиотека concurrent.futures в Python. Программа позволяет задавать количество процессов, что позволяет наблюдать за изменением производительности при увеличении числа потоков.
|
||||||
|
|
||||||
|
## Как работает код:
|
||||||
|
|
||||||
|
1. Импорт библиотек
|
||||||
|
- concurrent.futures помогает запускать параллельные задачи с использованием потоков
|
||||||
|
- time используется для измерения времени выполнения алгоритмов
|
||||||
|
- numpy используется для работы с матрицами и для вычислений
|
||||||
|
- argparse для обработки аргументов командной строки
|
||||||
|
|
||||||
|
2. Функция matrix_multiply_sequential(A, B)
|
||||||
|
- Выполняет последовательное умножение двух матриц A и B.
|
||||||
|
|
||||||
|
3. Функция worker(A, B, C, start_row, end_row)
|
||||||
|
- Выполняет умножение для части строк матрицы, параметры start_row и end_row определяют диапазон строк, которые нужно вычислить
|
||||||
|
|
||||||
|
4. Функция matrix_multiply_parallel(A, B, num_threads)
|
||||||
|
- Реализует параллельное умножение матриц
|
||||||
|
|
||||||
|
5. Функция benchmark(matrix_sizes, num_threads_list)
|
||||||
|
|
||||||
|
- Выполняет бенчмаркинг (измерение времени выполнения) для обоих методов умножения
|
||||||
|
|
||||||
|
## Результаты
|
||||||
|
|
||||||
|
Размер матриц: 100x100
|
||||||
|
Последовательное умножение заняло: 0.0558 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 2 потоками заняло: 0.0886 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 4 потоками заняло: 0.0876 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 8 потоками заняло: 0.0868 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 16 потоками заняло: 0.0914 секунд
|
||||||
|
|
||||||
|
Размер матриц: 300x300
|
||||||
|
Последовательное умножение заняло: 1.6149 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 2 потоками заняло: 2.4936 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 4 потоками заняло: 2.4383 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 8 потоками заняло: 2.4458 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 16 потоками заняло: 2.4899 секунд
|
||||||
|
|
||||||
|
Размер матриц: 500x500
|
||||||
|
Последовательное умножение заняло: 7.9416 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 2 потоками заняло: 11.8896 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 4 потоками заняло: 11.8901 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 8 потоками заняло: 12.0230 секунд
|
||||||
|
|
||||||
|
Параллельное умножение с 16 потоками заняло: 11.8548 секунд
|
||||||
|
|
||||||
|
|
||||||
|
## Выводы
|
||||||
|
Во всех случаях параллельный алгоритм выполняется дольше, чем последовательный. На рассматриваемых матрицах (100x100, 300x300, 500x500) последовательное умножение оказывается более выгодным. Это связано с тем, что накладные расходы на параллельное исполнение и синхронизацию между потоками превышают время, которое можно сэкономить за счёт многопоточности.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
Python main.py – threads 2 4 8 16
|
||||||
|
|
||||||
|
[Ссылка на демонстрацию работы программы](https://vk.com/video547368103_456239605?list=ln-ZAsjrYkuwZp6I4ghXC)
|
92
pupkov_alexey_lab_5/main.py
Normal file
92
pupkov_alexey_lab_5/main.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
import time
|
||||||
|
import numpy as np
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# Последовательное умножение
|
||||||
|
def matrix_multiply_sequential(A, B):
|
||||||
|
n = len(A)
|
||||||
|
C = [[0] * n for _ in range(n)]
|
||||||
|
|
||||||
|
# Транспонируем матрицу B для оптимального доступа по строкам
|
||||||
|
B_T = [[B[j][i] for j in range(n)] for i in range(n)]
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
A_row = A[i]
|
||||||
|
for j in range(n):
|
||||||
|
B_col = B_T[j]
|
||||||
|
sum_ij = 0
|
||||||
|
for k in range(n):
|
||||||
|
sum_ij += A_row[k] * B_col[k]
|
||||||
|
C[i][j] = sum_ij
|
||||||
|
|
||||||
|
return C
|
||||||
|
|
||||||
|
# Вычисляет подматрицу C
|
||||||
|
def worker(A, B, C, start_row, end_row):
|
||||||
|
n = len(A)
|
||||||
|
for i in range(start_row, end_row):
|
||||||
|
for j in range(n):
|
||||||
|
sum_ij = 0
|
||||||
|
for k in range(n):
|
||||||
|
sum_ij += A[i][k] * B[k][j]
|
||||||
|
C[i][j] = sum_ij
|
||||||
|
|
||||||
|
# Параллельное умножение матриц
|
||||||
|
def matrix_multiply_parallel(A, B, num_threads):
|
||||||
|
n = len(A)
|
||||||
|
C = [[0] * n for _ in range(n)]
|
||||||
|
|
||||||
|
# Разбиваем строки между потоками
|
||||||
|
rows_per_thread = n // num_threads
|
||||||
|
extra_rows = n % num_threads
|
||||||
|
row_splits = [rows_per_thread + (1 if i < extra_rows else 0) for i in range(num_threads)]
|
||||||
|
row_indices = [sum(row_splits[:i]) for i in range(num_threads + 1)]
|
||||||
|
|
||||||
|
# Параллельно выполняем умножение подматриц
|
||||||
|
with ThreadPoolExecutor(max_workers=num_threads) as executor:
|
||||||
|
futures = [
|
||||||
|
executor.submit(worker, A, B, C, row_indices[i], row_indices[i+1])
|
||||||
|
for i in range(num_threads)
|
||||||
|
]
|
||||||
|
for future in futures:
|
||||||
|
future.result()
|
||||||
|
|
||||||
|
return C
|
||||||
|
|
||||||
|
def benchmark(matrix_sizes, num_threads_list):
|
||||||
|
for size in matrix_sizes:
|
||||||
|
A = [[1] * size for _ in range(size)] # Матрицы, заполненные единицами для упрощения теста
|
||||||
|
B = [[1] * size for _ in range(size)]
|
||||||
|
print(f"\nРазмер матриц: {size}x{size}")
|
||||||
|
|
||||||
|
# Бенчмарк для последовательного алгоритма
|
||||||
|
start_time = time.time()
|
||||||
|
C_seq = matrix_multiply_sequential(A, B)
|
||||||
|
sequential_time = time.time() - start_time
|
||||||
|
print(f"Последовательное умножение заняло: {sequential_time:.4f} секунд")
|
||||||
|
|
||||||
|
# Бенчмарк для параллельного алгоритма
|
||||||
|
for num_threads in num_threads_list:
|
||||||
|
start_time = time.time()
|
||||||
|
C_par = matrix_multiply_parallel(A, B, num_threads)
|
||||||
|
parallel_time = time.time() - start_time
|
||||||
|
print(f"Параллельное умножение с {num_threads} потоками заняло: {parallel_time:.4f} секунд")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Запуск бенчмарков для умножения матриц.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--threads",
|
||||||
|
type=int,
|
||||||
|
nargs="+",
|
||||||
|
required=True,
|
||||||
|
help="Список количества потоков для параллельного алгоритма (например, --threads 1 2 4 8)"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Задание размеров матриц для тестов
|
||||||
|
matrix_sizes = [100, 300, 500]
|
||||||
|
num_threads_list = args.threads # Получаем список потоков из аргументов командной строки
|
||||||
|
|
||||||
|
# Запуск бенчмарка
|
||||||
|
benchmark(matrix_sizes, num_threads_list)
|
Loading…
Reference in New Issue
Block a user