Merge pull request 'mochalov_danila_lab_5' (#146) from mochalov_danila_lab_5 into main
Reviewed-on: #146
This commit is contained in:
commit
eaaeff7389
89
mochalov_danila_lab_5/main.py
Normal file
89
mochalov_danila_lab_5/main.py
Normal file
@ -0,0 +1,89 @@
|
||||
import random as rnd
|
||||
import time
|
||||
from multiprocessing import Pool
|
||||
|
||||
# Инициализируем матрицу результата нулями (так легче!)
|
||||
base_matrix = [[0 for i in range(500)] for j in range(500)]
|
||||
|
||||
# Функция для генерации квадратной матрицы заданного размера со случайными значениями от 0 до 100
|
||||
def generateMatrixWithSize(size):
|
||||
return [[rnd.randint(0, 100) for i in range(size)] for j in range(size)]
|
||||
|
||||
# Функция для вывода матрицы на экран
|
||||
def printMatrix(matrix):
|
||||
for row in matrix:
|
||||
print(*row, sep="\t")
|
||||
|
||||
# Функция для перемножения матриц без использования потоков (стандартный алгоритм)
|
||||
def multiplyMatrixOGWay(matrix1, matrix2):
|
||||
l1 = len(matrix1)
|
||||
l2 = len(matrix2)
|
||||
global base_matrix # Используем глобальную переменную для хранения результата
|
||||
result = base_matrix
|
||||
for i in range(l1):
|
||||
for j in range(l2):
|
||||
for k in range(l2):
|
||||
result[i][j] += matrix1[i][k] * matrix2[k][j]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Функция для перемножения части матриц в отдельном процессе (worker для Pool)
|
||||
def matrixMultiplyByOneProcess(args):
|
||||
matrix1_slice, matrix2, start_i, end_i = args # Распаковываем аргументы
|
||||
global base_matrix # Используем глобальную переменную для хранения результата
|
||||
|
||||
# Локальная ссылка для удобства
|
||||
result = base_matrix
|
||||
|
||||
for i in range(end_i-start_i):
|
||||
for j in range(len(matrix2[0])):
|
||||
for k in range(len(matrix2)):
|
||||
result[i + start_i][j] += matrix1_slice[i][k] * matrix2[k][j]
|
||||
|
||||
|
||||
# Функция для параллельного перемножения матриц с использованием процессов
|
||||
def matrixMultiplyWithProcesses(matrix1, matrix2, process_count):
|
||||
l1 = len(matrix1)
|
||||
|
||||
# Расчет количества строк на каждый процесс
|
||||
chunk_size = l1 // process_count
|
||||
remainder = l1 % process_count
|
||||
|
||||
args = []
|
||||
start_i = 0
|
||||
for i in range(process_count):
|
||||
end_i = start_i + chunk_size + (1 if i < remainder else 0)
|
||||
args.append((matrix1[start_i:end_i], matrix2, start_i, end_i))
|
||||
start_i = end_i
|
||||
|
||||
# Создание пула процессов и выполнение расчета
|
||||
with Pool(processes=process_count) as pool:
|
||||
pool.map(matrixMultiplyByOneProcess, args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix_sizes = [100, 300, 500]
|
||||
num_processes = [1, 5, 10]
|
||||
|
||||
for size in matrix_sizes:
|
||||
matrix1 = generateMatrixWithSize(size)
|
||||
matrix2 = generateMatrixWithSize(size)
|
||||
|
||||
# Замер времени для стандартного умножения
|
||||
base_matrix = [[0 for i in range(size)] for j in range(size)] # Очищаем перед каждым запуском.
|
||||
start_time = time.time()
|
||||
multiplyMatrixOGWay(matrix1, matrix2)
|
||||
end_time = time.time()
|
||||
print(f"Обычный режим. Размер матрицы: {size}. {end_time - start_time} сек.")
|
||||
|
||||
# Замер времени для параллельного умножения с разным количеством процессов
|
||||
for processes in num_processes:
|
||||
base_matrix = [[0 for i in range(size)] for j in range(size)] # Очищаем перед каждым запуском.
|
||||
start_time = time.time()
|
||||
matrixMultiplyWithProcesses(matrix1, matrix2, processes)
|
||||
end_time = time.time()
|
||||
print(f"Параллельный режим. Размер матрицы: {size}. Количество процессов: {processes}. {end_time - start_time} сек.")
|
||||
|
||||
print("\n\n")
|
34
mochalov_danila_lab_5/readme.md
Normal file
34
mochalov_danila_lab_5/readme.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Лабораторная работа №5
|
||||
#### ПИбд-42. Мочалов Данила.
|
||||
|
||||
#### Выполнение
|
||||
Были реализованы два алгоритма для перемножения матриц: обычный и паралелльный. Параллельный алгоритм использует multiprocessing.Pool для разделения вычислений между несколькими процессами.
|
||||
|
||||
#### Результаты бенчмарков:
|
||||
|
||||
Были проведены тесты для матриц размером 100x100, 300x300 и 500x500 элементов с разным количеством процессов (1, 5, 10). Результаты представлены в таблице:
|
||||
|
||||
| Размер матрицы | Алгоритм | Кол-во процессов |Время (сек.)|
|
||||
|----------------|------------|------------------|------------|
|
||||
| 100x100 |Обычный |- |0.21 |
|
||||
| 100x100 |Параллельный|1 |0.59 |
|
||||
| 100x100 |Параллельный|5 |0.34 |
|
||||
| 100x100 |Параллельный|10 |0.32 |
|
||||
| 300x300 |Обычный |- |6.59 |
|
||||
| 300x300 |Параллельный|1 |7.03 |
|
||||
| 300x300 |Параллельный|5 |2.00 |
|
||||
| 300x300 |Параллельный|10 |1.54 |
|
||||
| 500x500 |Обычный |- |29.81 |
|
||||
| 500x500 |Параллельный|1 |33.83 |
|
||||
| 500x500 |Параллельный|5 |8.57 |
|
||||
| 500x500 |Параллельный|10 |5.67 |
|
||||
---------------------------------------------------------------
|
||||
#### Анализ
|
||||
- Для маленьких матриц (100x100) параллельный алгоритм с одним процессом работает медленнее последовательного. Это связано с накладными расходами на создание и управление процессом, которые превышают выигрыш от параллелизма.
|
||||
|
||||
- С увеличением размера матрицы эффективность параллельного алгоритма возрастает. Для матриц 300x300 и 500x500 наблюдается значительное ускорение по сравнению с последовательным алгоритмом.
|
||||
|
||||
- Количество процессов, обеспечивающее максимальное ускорение, зависит от размера матрицы и аппаратных возможностей системы. В данном случае, для матрицы 300x300 использование 10 процессов дает лучший результат, а для 500x500 - тоже 10. Дальнейшее увеличение количества процессов может привести к снижению производительности из-за увеличения накладных расходов на межпроцессное взаимодействие.
|
||||
|
||||
#### Демонстрация
|
||||
[Доступна по ссылке](https://drive.google.com/file/d/1GxPw9syJVnxb65zP6uQVNYyLjZ-HrfOo/view?usp=sharing)
|
Loading…
Reference in New Issue
Block a user