Merge pull request 'yakovlev_maxim_lab_5' (#428) from yakovlev_maxim_lab_5 into main

Reviewed-on: #428
This commit was merged in pull request #428.
This commit is contained in:
2025-12-08 23:12:00 +04:00
2 changed files with 138 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
## Лабораторная работа №5
### Описание лабораторной работы
Реализация последовательного и параллельного алгоритмов умножения квадратных матриц.
- multiply_sequential - реализация последовательного алгоритма умножения матриц
- multiply - реализация параллельного алгоритма умножения матриц
- run_benchmark - метод запуска бенчмарка с выводом всей нужной информации
### Результаты тестирования
Оба алгоритма работают с матрицами, заполненными целыми числами.
Тестирование проведено для размеров: **100×100**, **300×300**, **500×500**.
Количество потоков в параллельной версии: **2 и 4**.
| Размер матрицы | Последовательно | 2 потока | 4 потока |
|----------------|------------------|-----------|-----------|
| 100×100 | 0.518 с | 0.312 с | 0.312 с |
| 300×300 | 13.932 с | 8.209 с | 8.416 с |
| 500×500 | 65.786 с | 37.325 с | 37.595 с |
### Наблюдения
1. **Параллельная версия работает значительно быстрее**, чем последовательная.
2. Уже при **2 потоках** достигается почти максимальное ускорение.
3. Переход от 2 к 4 потокам **практически не даёт прироста**
4. Оптимальная конфигурация 1-2 потока. Дальнейшее увеличение потоков не дает преимущества
[Ссылка на видео](https://vkvideo.ru/video-233039857_456239021?list=ln-lVxcVooa9DTzJiFwrg)

View File

@@ -0,0 +1,113 @@
import random
import threading
import time
import numpy as np
def generate_matrix(n):
return np.random.randint(1, 10, size=(n, n), dtype=np.int64)
class matrix_multiplier:
def __init__(self):
pass
#Последовательное умножение
def multiply_sequential(self, A, B):
n = len(A)
C = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(n):
for k in range(n):
C[i][j] += A[i][k] * B[k][j]
return C
#Умножение двух матриц с использованием заданного числа потоков
def multiply(self, matrix_a: np.ndarray, matrix_b: np.ndarray, thread_num: int = 1) -> np.ndarray:
if matrix_a.shape[1] != matrix_b.shape[0]:
raise ValueError("Невозможно умножить матрицы: несовпадение внутренних размеров")
n_rows = matrix_a.shape[0]
n_cols = matrix_b.shape[1]
result_matrix = np.zeros((n_rows, n_cols), dtype=np.int64)
# Определяем, сколько строк достанется каждому потоку
base_rows = n_rows // thread_num
extra = n_rows % thread_num
# Вычисление строк результирующей матрицы
def _process_chunk(start_idx: int, end_idx: int):
for i in range(start_idx, end_idx):
for j in range(n_cols):
acc = 0
for k in range(matrix_a.shape[1]):
acc += matrix_a[i, k] * matrix_b[k, j]
result_matrix[i, j] = acc
active_threads = []
current_start = 0
for tid in range(thread_num):
# Первые 'extra' потоков получают на одну строку больше
chunk_end = current_start + base_rows + (1 if tid < extra else 0)
if current_start < chunk_end: # Защита от пустых диапазонов
thread = threading.Thread(
target=_process_chunk,
args=(current_start, chunk_end)
)
active_threads.append(thread)
thread.start()
current_start = chunk_end
# Ожидаем завершения всех потоков
for t in active_threads:
t.join()
return result_matrix
def run_benchmark():
sizes = [100, 300, 500]
thread_counts = [2, 4]
mm = matrix_multiplier()
for n in sizes:
print(f"\n{'='*50}")
print(f" Размер матрицы: {n}x{n}")
print(f"{'='*50}")
# Генерируем целочисленные матрицы
A = generate_matrix(n)
B = generate_matrix(n)
# --- Последовательная версия ---
print("\n Последовательное умножение...")
start = time.perf_counter()
C_seq = mm.multiply_sequential(A, B)
time_seq = time.perf_counter() - start
print(f" Время: {time_seq:.3f} сек")
# --- Параллельная версия ---
for threads in thread_counts:
print(f"\n Параллельное умножение ({threads} потоков)...")
start = time.perf_counter()
C_par = mm.multiply(A, B, thread_num=threads)
time_par = time.perf_counter() - start
print(f" Время: {time_par:.3f} сек")
# Проверка корректности
if np.array_equal(C_seq, C_par):
print("Результаты совпадают!")
else:
print("Ошибка: результаты не совпадают!")
if __name__ == "__main__":
A = generate_matrix(100)
B = generate_matrix(100)
mm = matrix_multiplier()
C = mm.multiply_sequential(A,B)
run_benchmark()