diff --git a/kosheev_maksim_lab_5/main.py b/kosheev_maksim_lab_5/main.py new file mode 100644 index 0000000..f1f0b86 --- /dev/null +++ b/kosheev_maksim_lab_5/main.py @@ -0,0 +1,67 @@ +import numpy as np +from multiprocessing import Pool +import time + +# Генерация квадратной матрицы случайными значениями +def generate_matrix(size): + return np.random.randint(1, 10, (size, size)) + + +# Обычное умножение матриц +def matrix_multiply_sequential(A, B): + size = A.shape[0] + C = np.zeros((size, size), dtype=int) + for i in range(size): + for j in range(size): + C[i, j] = sum(A[i, k] * B[k, j] for k in range(size)) + return C + +def multiply_row(args): + A, B, row = args + return np.dot(A[row, :], B) + + +# Параллельное умножение матриц +def parallel_matrix_multiply(A, B, num_processes): + n = A.shape[0] + C = np.zeros((n, n)) + + # Создаем пул процессов + with Pool(processes=num_processes) as pool: + results = pool.map(multiply_row, [(A, B, i) for i in range(n)]) + + # Записываем результат + for i, row in enumerate(results): + C[i, :] = row + + return C + + +# Бенчмарк функции +def benchmark(matrix_size, num_processes_list): + A = np.random.randint(0, 10, (matrix_size, matrix_size)) + B = np.random.randint(0, 10, (matrix_size, matrix_size)) + + # Последовательное умножение + start_time = time.time() + C_seq = np.dot(A, B) + sequential_time = time.time() - start_time + print(f"Sequential time for {matrix_size}x{matrix_size}: {sequential_time:.4f} seconds") + + # Параллельное умножение + for num_processes in num_processes_list: + start_time = time.time() + C_par = parallel_matrix_multiply(A, B, num_processes) + parallel_time = time.time() - start_time + speedup = sequential_time / parallel_time + print(f"Parallel time with {num_processes} processes: {parallel_time:.4f} seconds, Speedup: {speedup:.2f}") + + +if __name__ == '__main__': + # Запуск бенчмарков + matrix_sizes = [100, 500, 1000, 2500, 400] + num_processes_list = [1, 2, 4, 6, 8, 12, 16] + + for size in matrix_sizes: + print(f"\n--- Benchmark for {size}x{size} Matrix ---") + benchmark(size, num_processes_list) \ No newline at end of file diff --git a/kosheev_maksim_lab_5/readmy.md b/kosheev_maksim_lab_5/readmy.md new file mode 100644 index 0000000..e91aa79 --- /dev/null +++ b/kosheev_maksim_lab_5/readmy.md @@ -0,0 +1,89 @@ +# Лабораторная работа №5 - Параллельное умножение матриц + +## Задание +В данной лабораторной работе было необходимо реализовать умножение двух квадратных матриц двумя способами: +1. Последовательное умножение. +2. Параллельное умножение с возможностью задания количества потоков. + +Основная цель — изучить эффект параллельных вычислений и оценить прирост производительности при увеличении количества потоков. + +## Запуск +Для запуска алгоритма умножения матриц потребуется Python и модуль `multiprocessing`. + +Запуск теста производительности: +``` + python matrix_multiplication_benchmark.py +``` + +## Результаты + +Ниже представлены результаты бенчмарков для различных размеров матриц и разного количества потоков: + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **100x100** | 1 | 0.0000 s | 0.2030 s | 0.00 | +| | 2 | 0.0000 s | 0.1770 s | 0.00 | +| | 4 | 0.0000 s | 0.1976 s | 0.00 | +| | 6 | 0.0000 s | 0.3170 s | 0.00 | +| | 8 | 0.0000 s | 0.2330 s | 0.00 | +| | 12 | 0.0000 s | 0.2570 s | 0.00 | +| | 16 | 0.0000 s | 0.2705 s | 0.00 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **500x500** | 1 | 0.0621 s | 0.2400 s | 0.26 | +| | 2 | 0.0621 s | 0.2270 s | 0.27 | +| | 4 | 0.0621 s | 0.2320 s | 0.27 | +| | 6 | 0.0621 s | 0.2744 s | 0.23 | +| | 8 | 0.0621 s | 0.3260 s | 0.19 | +| | 12 | 0.0621 s | 0.4322 s | 0.14 | +| | 16 | 0.0621 s | 0.5961 s | 0.10 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **1000x1000** | 1 | 0.6100 s | 0.8320 s | 0.73 | +| | 2 | 0.6100 s | 0.5252 s | 1.16 | +| | 4 | 0.6100 s | 0.4431 s | 1.38 | +| | 6 | 0.6100 s | 0.4750 s | 1.28 | +| | 8 | 0.6100 s | 0.5668 s | 1.08 | +| | 12 | 0.6100 s | 0.7913 s | 0.77 | +| | 16 | 0.6100 s | 0.9752 s | 0.63 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **2500x2500** | 1 | 15.6168 s | 14.9276 s | 1.05 | +| | 2 | 15.6168 s | 10.0759 s | 1.55 | +| | 4 | 15.6168 s | 6.5090 s | 2.40 | +| | 6 | 15.6168 s | 6.1926 s | 2.52 | +| | 8 | 15.6168 s | 5.7073 s | 2.74 | +| | 12 | 15.6168 s | 5.7048 s | 2.74 | +| | 16 | 15.6168 s | 6.1797 s | 2.53 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **4000x4000** | 1 | 153.4893 s | 142.6276 s | 1.08 | +| | 2 | 153.4893 s | 72.1959 s | 2.13 | +| | 4 | 153.4893 s | 41.6678 s | 3.68 | +| | 6 | 153.4893 s | 33.3039 s | 4.61 | +| | 8 | 153.4893 s | 30.3821 s | 5.05 | +| | 12 | 153.4893 s | 27.2013 s | 5.64 | +| | 16 | 153.4893 s | 29.0246 s | 5.29 | + +| Количество потоков | Загрузка процессора (%) | +|--------------------|-------------------------| +| 1 поток | 12% | +| 2 потока | 22-24% | +| 4 потока | 44-46% | +| 6 потоков | 64-67% | +| 8 потоков | 85-87% | +| 12 потоков | 92-96% | +| 16 потоков | 95-96% | +## Выводы +Из результатов видно, что ускорение при использовании параллельного алгоритма зависит от размера матрицы и количества потоков: +- Для небольших матриц (например, 100x100) параллельный алгоритм не дает значительного ускорения и даже может работать медленнее из-за накладных расходов на создание потоков. +- Для больших матриц (например, 4000x4000) параллельный алгоритм дает существенное ускорение, достигая оптимальных значений на 8–12 потоках. +- Если количество потоков превышает количество ядер процессора, наблюдается ухудшение производительности, так как накладные расходы на управление потоками начинают превышать прирост от параллелизма. +- Загруженность процессора: При увеличении количества потоков наблюдается значительное повышение загрузки процессора. На конфигурации с 16 потоками процессор работает на 95-96%, что указывает на высокую эффективность использования доступных ядер. Однако увеличение числа потоков сверх количества доступных ядер (например, использование 16 потоков на 8-ядерном процессоре) не дает заметного увеличения производительности и может даже привести к ее снижению из-за конкуренции за ресурсы. +- Таким образом, для эффективного параллельного умножения матриц важно учитывать размер данных и правильно подбирать количество потоков. + +## [Видео](https://disk.yandex.ru/i/aYvYD_fHQLfdZQ)