Merge pull request 'nikolaeva_yana_lab_5' (#339) from nikolaeva_yana_lab_5 into nikolaeva_yana_lab_4
Reviewed-on: #339
This commit is contained in:
commit
92226b1691
62
nikolaeva_yana_lab_5/README.md
Normal file
62
nikolaeva_yana_lab_5/README.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Лабораторная работа: Умножение матриц
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
**Цель работы** – реализовать последовательный и параллельный алгоритмы умножения матриц, а также сравнить их производительность на больших квадратных матрицах.
|
||||||
|
|
||||||
|
### Задачи:
|
||||||
|
1. Реализовать последовательный алгоритм умножения матриц.
|
||||||
|
2. Реализовать параллельный алгоритм, позволяющий задавать количество потоков вручную.
|
||||||
|
3. Провести тесты на матрицах размером 100x100, 300x300 и 500x500.
|
||||||
|
4. Сделать выводы о влиянии размеров матриц и количества потоков на производительность алгоритмов.
|
||||||
|
|
||||||
|
## Теоретическое обоснование
|
||||||
|
|
||||||
|
Умножение матриц — вычислительно сложная операция с асимптотической сложностью O(N³) для матриц размером N×N.
|
||||||
|
Для ускорения вычислений используется параллелизация, где каждая часть вычислений выполняется в отдельном потоке.
|
||||||
|
Однако эффективность параллельного подхода зависит от размеров задачи и числа потоков.
|
||||||
|
|
||||||
|
## Реализация
|
||||||
|
|
||||||
|
1. **Последовательный алгоритм**:
|
||||||
|
- Выполняет вычисления поэлементно для каждой строки первой матрицы и каждого столбца второй.
|
||||||
|
- Этот алгоритм не использует дополнительные ресурсы, кроме одного потока, и подходит для небольших задач.
|
||||||
|
|
||||||
|
2. **Параллельный алгоритм**:
|
||||||
|
- Делит строки первой матрицы на группы, каждая из которых обрабатывается в отдельном потоке.
|
||||||
|
- Реализован с использованием модуля `multiprocessing` для управления потоками.
|
||||||
|
- Число потоков задается вручную для возможности анализа производительности.
|
||||||
|
|
||||||
|
## Результаты тестирования
|
||||||
|
|
||||||
|
### Условия тестирования
|
||||||
|
- Размеры матриц: 100x100, 300x300, 500x500.
|
||||||
|
- Количество потоков: 1 (последовательное выполнение), 2, 4.
|
||||||
|
- Диапазон значений элементов матриц: от 0 до 200.
|
||||||
|
|
||||||
|
|
||||||
|
## Выводы
|
||||||
|
|
||||||
|
1. **Последовательный алгоритм**:
|
||||||
|
- Подходит для матриц небольшого размера (100x100), где накладные расходы на параллелизацию превышают выигрыши от многопоточности.
|
||||||
|
|
||||||
|
2. **Параллельный алгоритм**:
|
||||||
|
- Значительно ускоряет умножение матриц с увеличением их размера.
|
||||||
|
- Для матриц 500x500 ускорение в 2–2.5 раза при переходе от 1 потока к 4 потокам.
|
||||||
|
|
||||||
|
3. **Влияние числа потоков**:
|
||||||
|
- Оптимальное число потоков зависит от размера задачи и доступных ресурсов.
|
||||||
|
- Слишком большое количество потоков может привести к росту накладных расходов.
|
||||||
|
|
||||||
|
4. **Закономерности**:
|
||||||
|
- Накладные расходы на управление потоками минимальны для больших задач.
|
||||||
|
- Параллельные алгоритмы демонстрируют преимущество на задачах с высокой вычислительной сложностью.
|
||||||
|
|
||||||
|
## Заключение
|
||||||
|
|
||||||
|
Лабораторная работа подтвердила, что параллельные алгоритмы значительно эффективнее на больших данных.
|
||||||
|
Однако для небольших задач последовательный алгоритм остается предпочтительным из-за отсутствия накладных расходов.
|
||||||
|
В реальных приложениях важно учитывать баланс между размером задачи и доступными вычислительными ресурсами.
|
||||||
|
|
||||||
|
## Видео
|
||||||
|
https://cloud.mail.ru/public/fykM/jy3KEZBZM
|
BIN
nikolaeva_yana_lab_5/img.png
Normal file
BIN
nikolaeva_yana_lab_5/img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
66
nikolaeva_yana_lab_5/main.py
Normal file
66
nikolaeva_yana_lab_5/main.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import numpy as np
|
||||||
|
import time
|
||||||
|
from multiprocessing import Pool, cpu_count
|
||||||
|
|
||||||
|
|
||||||
|
def generate_matrix(size, value_range=(0, 200)):
|
||||||
|
return np.random.randint(value_range[0], value_range[1], (size, size))
|
||||||
|
|
||||||
|
|
||||||
|
def multiply_matrices_sequential(matrix_a, matrix_b):
|
||||||
|
size = len(matrix_a)
|
||||||
|
result = np.zeros((size, size), dtype=int)
|
||||||
|
for i in range(size):
|
||||||
|
for j in range(size):
|
||||||
|
for k in range(size):
|
||||||
|
result[i][j] += matrix_a[i][k] * matrix_b[k][j]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def worker_multiply(args):
|
||||||
|
i_range, matrix_a, matrix_b, size = args
|
||||||
|
result_part = np.zeros((len(i_range), size), dtype=int)
|
||||||
|
for idx, i in enumerate(i_range):
|
||||||
|
for j in range(size):
|
||||||
|
for k in range(size):
|
||||||
|
result_part[idx][j] += matrix_a[i][k] * matrix_b[k][j]
|
||||||
|
return result_part
|
||||||
|
|
||||||
|
|
||||||
|
def multiply_matrices_parallel(matrix_a, matrix_b, num_threads):
|
||||||
|
size = len(matrix_a)
|
||||||
|
step = size // num_threads
|
||||||
|
ranges = [range(i, min(i + step, size)) for i in range(0, size, step)]
|
||||||
|
|
||||||
|
with Pool(processes=num_threads) as pool:
|
||||||
|
results = pool.map(worker_multiply, [(i_range, matrix_a, matrix_b, size) for i_range in ranges])
|
||||||
|
|
||||||
|
return np.vstack(results)
|
||||||
|
|
||||||
|
def benchmark(matrix_a, matrix_b, num_threads):
|
||||||
|
print(f"\nМатрицы размера {len(matrix_a)}x{len(matrix_a)}:")
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
result_seq = multiply_matrices_sequential(matrix_a, matrix_b)
|
||||||
|
sequential_time = time.time() - start
|
||||||
|
print(f"Последовательное умножение заняло: {sequential_time:.4f} секунд")
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
result_par = multiply_matrices_parallel(matrix_a, matrix_b, num_threads)
|
||||||
|
parallel_time = time.time() - start
|
||||||
|
print(f"Параллельное умножение ({num_threads} потоков) заняло: {parallel_time:.4f} секунд")
|
||||||
|
|
||||||
|
assert np.array_equal(result_seq, result_par), "Ошибка: результаты не совпадают!"
|
||||||
|
print("Результаты совпадают.")
|
||||||
|
|
||||||
|
return sequential_time, parallel_time
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sizes = [100, 300, 500]
|
||||||
|
num_threads = min(cpu_count(), 4)
|
||||||
|
|
||||||
|
for size in sizes:
|
||||||
|
matrix_a = generate_matrix(size)
|
||||||
|
matrix_b = generate_matrix(size)
|
||||||
|
benchmark(matrix_a, matrix_b, num_threads)
|
Loading…
Reference in New Issue
Block a user