Merge pull request 'chernyshov_nikita_lab_5 is ready' (#350) from chernyshov_nikita_lab_5 into main
Reviewed-on: #350
This commit is contained in:
commit
5849266f9b
58
chernyshov_nikita_lab_5/README.md
Normal file
58
chernyshov_nikita_lab_5/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Лабораторная работа 5: Умножение матриц
|
||||
|
||||
## Описание
|
||||
|
||||
**Цель работы** – реализовать и сравнить производительность последовательного и параллельного алгоритмов умножения матриц на больших массивах данных.
|
||||
|
||||
### Задачи:
|
||||
1. Разработать последовательный алгоритм умножения матриц.
|
||||
2. Реализовать параллельный алгоритм с возможностью настройки числа потоков.
|
||||
3. Провести тестирование обоих подходов на матрицах размером 100x100, 300x300 и 500x500.
|
||||
4. Выполнить анализ производительности, изучив зависимость времени выполнения от размера матриц и количества потоков, и сформулировать выводы.
|
||||
|
||||
## Теоретическое обоснование
|
||||
|
||||
Операция умножения матриц широко применяется в задачах вычислительного характера, таких как обработка изображений, машинное обучение и физическое моделирование. Сложность умножения матриц размером
|
||||
N×N составляет O(N^3), что приводит к резкому росту времени вычислений с увеличением размера матриц. Для ускорения работы можно использовать параллельные алгоритмы, распределяющие вычисления между несколькими потоками.
|
||||
|
||||
## Реализация
|
||||
|
||||
1. **Последовательный алгоритм:** Реализован в модуле sequential.py. Алгоритм вычисляет каждый элемент результирующей матрицы поэлементно, складывая произведения соответствующих элементов строк и столбцов исходных матриц.
|
||||
|
||||
2. **Параллельный алгоритм:** Представлен в модуле parallel.py. Он использует многопоточность, разделяя вычисления на несколько потоков, где каждый поток обрабатывает определённый блок строк результирующей матрицы. Пользователь может задавать количество потоков для оптимизации производительности с учётом размера матриц и доступных ресурсов.
|
||||
|
||||
## Результаты тестирования
|
||||
|
||||
Тестирование проводилось на матрицах размером 100x100, 300x300 и 500x500 с различным числом потоков. Было проанализировано влияние количества потоков на производительность алгоритма.
|
||||
|
||||
## Скриншоты результатов
|
||||
|
||||
### Результат бенчамарка при 1 потоке:
|
||||
![img1.png](img1.png)
|
||||
|
||||
### Результат бенчамарка при 2 потоках:
|
||||
![img2.png](img2.png)
|
||||
|
||||
### Результат бенчамарка при 4 потоках:
|
||||
![img3.png](img3.png)
|
||||
|
||||
### Результат бенчамарка при 8 потоках:
|
||||
![img4.png](img4.png)
|
||||
|
||||
## Выводы
|
||||
|
||||
1. **Эффективность параллельного алгоритма**: Использование многопоточности в параллельном алгоритме показало значительное ускорение по сравнению с последовательным методом, особенно на матрицах больших размеров. Например, для матриц размером 500x500 параллельный алгоритм с 4 потоками оказался более чем вдвое быстрее последовательного.
|
||||
|
||||
2. **Влияние количества потоков**: Увеличение числа потоков сокращает время выполнения, но этот эффект ограничен. Для небольших матриц (100x100) использование более 2 потоков практически не улучшает производительность. На матрицах среднего и большого размера (300x300 и 500x500) оптимальный результат достигался при использовании 4 потоков, так как это позволяло равномерно распределить вычислительную нагрузку.
|
||||
|
||||
3. **Закономерности и ограничения**: Эффективность параллельного умножения матриц ограничена накладными расходами на управление потоками. Для небольших задач эти расходы могут нивелировать преимущества параллелизации. Однако на больших данных задача лучше масштабируется, что делает параллельный подход значительно более выгодным.
|
||||
|
||||
4. **Рекомендации по использованию**: Для работы с большими матрицами в реальных задачах рекомендуется использовать параллельные алгоритмы, подбирая оптимальное число потоков в зависимости от объёма задачи и доступных вычислительных ресурсов.
|
||||
|
||||
## Заключение
|
||||
|
||||
Выполнение лабораторной работы показало, что параллельные алгоритмы значительно ускоряют умножение матриц на больших данных. Однако для достижения максимальной эффективности важно учитывать размер задачи и оптимально выбирать количество потоков. Полученные результаты подтверждают, что параллельный подход предпочтителен для работы с крупными матрицами, тогда как для небольших задач затраты на управление потоками могут свести его преимущества на нет.
|
||||
|
||||
## Видео
|
||||
|
||||
https://vkvideo.ru/video286865610_456239228?list=ln-RciNpMoyWby0uMIZoa
|
27
chernyshov_nikita_lab_5/benchmark.py
Normal file
27
chernyshov_nikita_lab_5/benchmark.py
Normal file
@ -0,0 +1,27 @@
|
||||
import time
|
||||
import random
|
||||
from matrix_multiplication.sequential import matrix_multiply_sequential
|
||||
from matrix_multiplication.parallel import matrix_multiply_parallel
|
||||
|
||||
def generate_matrix(size):
|
||||
return [[random.randint(0, 10) for _ in range(size)] for _ in range(size)]
|
||||
|
||||
def benchmark(matrix_size, num_threads):
|
||||
A = generate_matrix(matrix_size)
|
||||
B = generate_matrix(matrix_size)
|
||||
|
||||
start = time.time()
|
||||
matrix_multiply_sequential(A, B)
|
||||
sequential_time = time.time() - start
|
||||
|
||||
start = time.time()
|
||||
matrix_multiply_parallel(A, B, num_threads)
|
||||
parallel_time = time.time() - start
|
||||
|
||||
print(f"Размер матрицы: {matrix_size}x{matrix_size}")
|
||||
print(f"Последовательное время: {sequential_time:.5f} сек")
|
||||
print(f"Параллельное время ({num_threads} потоков): {parallel_time:.5f} сек")
|
||||
|
||||
if __name__ == "__main__":
|
||||
for size in [100, 300, 500]:
|
||||
benchmark(size, num_threads=8)
|
BIN
chernyshov_nikita_lab_5/img1.png
Normal file
BIN
chernyshov_nikita_lab_5/img1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
chernyshov_nikita_lab_5/img2.png
Normal file
BIN
chernyshov_nikita_lab_5/img2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
chernyshov_nikita_lab_5/img3.png
Normal file
BIN
chernyshov_nikita_lab_5/img3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
chernyshov_nikita_lab_5/img4.png
Normal file
BIN
chernyshov_nikita_lab_5/img4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
21
chernyshov_nikita_lab_5/matrix_multiplication/parallel.py
Normal file
21
chernyshov_nikita_lab_5/matrix_multiplication/parallel.py
Normal file
@ -0,0 +1,21 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
def matrix_multiply_parallel(A, B, num_threads=1):
|
||||
n = len(A)
|
||||
result = [[0] * n for _ in range(n)]
|
||||
|
||||
def worker(start, end):
|
||||
for i in range(start, end):
|
||||
for j in range(n):
|
||||
result[i][j] = sum(A[i][k] * B[k][j] for k in range(n))
|
||||
|
||||
chunk_size = n // num_threads
|
||||
with ThreadPoolExecutor(max_workers=num_threads) as executor:
|
||||
futures = [
|
||||
executor.submit(worker, i * chunk_size, (i + 1) * chunk_size)
|
||||
for i in range(num_threads)
|
||||
]
|
||||
for future in futures:
|
||||
future.result()
|
||||
|
||||
return result
|
@ -0,0 +1,9 @@
|
||||
def matrix_multiply_sequential(A, B):
|
||||
n = len(A)
|
||||
result = [[0] * n for _ in range(n)]
|
||||
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
result[i][j] = sum(A[i][k] * B[k][j] for k in range(n))
|
||||
|
||||
return result
|
Loading…
Reference in New Issue
Block a user