Исследовать эффективность параллельного выполнения программы умножения квадратных матриц с использованием технологии OpenMP. Определить зависимость времени выполнения от размера матриц и количества потоков.
Файлы:
- A_matrix.txt — матрица A
- B_matrix.txt — матрица B
Матрицы генерируются случайным образом в программе.
- Result.txt — результат перемножения матриц
- время выполнения программы
- объем задачи
- проверка корректности (Python, NumPy)
#include <iostream>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <omp.h>
void multiply(int n, int A[2000][2000], int B[2000][2000], int C[2000][2000])
{
int i, j, k;
#pragma omp parallel for
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
C[i][j] = 0;
for (k = 0; k < n; k++)
C[i][j] += A[i][k] * B[k][j];
}
}
int main()
{
int n;
int threads;
std::cout << "Enter matrix size: ";
std::cin >> n;
std::cout << "Enter number of threads: ";
std::cin >> threads;
omp_set_num_threads(threads);
std::cout << "Max available threads: " << omp_get_max_threads() << "\n";
static int A[2000][2000];
static int B[2000][2000];
static int C[2000][2000];
std::ofstream Afile("A_matrix.txt");
std::ofstream Bfile("B_matrix.txt");
srand(time(0));
Afile << n << "\n";
Bfile << n << "\n";
int i, j;
// генерация и запись
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
A[i][j] = rand() % 10;
B[i][j] = rand() % 10;
Afile << A[i][j] << " ";
Bfile << B[i][j] << " ";
}
Afile << "\n";
Bfile << "\n";
}
Afile.close();
Bfile.close();
double start = omp_get_wtime();
multiply(n, A, B, C);
double end = omp_get_wtime();
std::ofstream Cfile("Result.txt");
Cfile << n << "\n";
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
Cfile << C[i][j] << " ";
Cfile << "\n";
}
Cfile.close();
double t = end - start;
std::cout << "\n RESULT \n";
std::cout << "Matrix size: " << n << " x " << n << "\n";
std::cout << "Threads: " << threads << "\n";
std::cout << "Time: " << t << " sec\n";
std::cout << "Operations: " << (long long)n * n * n << "\n";
return 0;
}import numpy as np
A = np.loadtxt("A_matrix.txt", skiprows=1)
B = np.loadtxt("B_matrix.txt", skiprows=1)
C = np.loadtxt("Result.txt", skiprows=1)
R = A @ B
if (R == C).all():
print("Matrix multiplication is correct.")
else:
print("Matrix multiplication is wrong.")| N (размер) | Потоки | Время (сек) | Объём задачи (N³) |
|---|---|---|---|
| 200 | 1 | 0,054898 | 8000000 |
| 200 | 2 | 0,0617131 | 8000000 |
| 200 | 4 | 0,0585114 | 8000000 |
| 400 | 1 | 0,364215 | 64000000 |
| 400 | 2 | 0,472091 | 64000000 |
| 400 | 4 | 0,453813 | 64000000 |
| 800 | 1 | 3,99106 | 512000000 |
| 800 | 2 | 3,29522 | 512000000 |
| 800 | 4 | 2,97407 | 512000000 |
| 1200 | 1 | 12,8639 | 1728000000 |
| 1200 | 2 | 11,8587 | 1728000000 |
| 1200 | 4 | 8,81476 | 1728000000 |
| 1400 | 1 | 21,1614 | 2744000000 |
| 1400 | 2 | 23,8853 | 2744000000 |
| 1400 | 4 | 22,8413 | 2744000000 |
| 1600 | 1 | 30,529 | 4096000000 |
| 1600 | 2 | 28,3173 | 4096000000 |
| 1600 | 4 | 23,9287 | 4096000000 |
В ходе экспериментов была проверена зависимость времени выполнения программы от размера матрицы и количества потоков.
При небольших размерах матриц (N = 200 и 400) увеличение количества потоков не даёт ускорения. Более того, время выполнения даже немного увеличивается. Это связано с тем, что на маленьких задачах затраты на создание потоков больше, чем польза от распараллеливания.
При размере матрицы N = 800 уже начинает наблюдаться ускорение. При использовании 4 потоков программа работает быстрее, чем при одном.
При больших размерах матриц (N = 1200, 1400, 1600) ускорение становится заметным. Чем больше потоков, тем меньше время выполнения программы.
Таким образом, распараллеливание эффективно только для задач с большим объёмом данных.
В данной работе была реализована параллельная версия умножения матриц с использованием OpenMP.
В результате экспериментов было установлено, что при небольших размерах матриц распараллеливание не даёт выигрыша по времени. Однако при увеличении размера задачи использование нескольких потоков позволяет ускорить выполнение программы.
Это показывает, что параллельные вычисления имеет смысл применять для больших задач.
