目录
1. 实验内容与方法
- 初始化数组。初始化三个double矩阵matrix_a,matrix_b和result,矩阵的行和列可以根据数据量大小自行调整。数组中的值使用c++11中的random类随机生成0到1之间的double值。
- 程序计时。使用c++11中的std::chrono库,使用system_clock表示当前的系统时钟,系统中运行的所有进程使用now()得到的时间是一致的。
- 串行执行数组相乘。遍历两个矩阵,使用矩阵乘法,将存储的结果放到
- 并行执行数组相乘。使用openmp将for循环设置为多线程,线程数根据实验内容进行调整。
- 线程数不变,修改矩阵大小。从6000 * 6000修改为8000 * 6000和8000 * 8000,统计运行时间。
- 矩阵大小不变,修改线程数。分别设置线程数为2、4、8个,统计运行时间。
2. 实验过程
实验设备CPU(i7-7700 3.6GHz, 8核),内存16G,操作系统Ubuntu 18.04,IDE CLion。
2.1 运行时间
分别控制矩阵大小和并行线程数进行实验。经过长时间的代码运行计时,得到以下的实验结果表格。
运行时间/秒 | 6000 * 6000 | 8000 * 6000 | 8000 * 8000 |
串行执行 | 1222.05 | 2603.9 | 3835.77 |
2核 | 575.985 | 1133.83 | 1859.81 |
4核 | 295.408 | 568.993 | 869.143 |
8核 | 273.935 | 497.045 | 921.517 |
2.2 加速比
加速比 | 6000 * 6000 | 8000 * 6000 | 8000 * 8000 |
串行执行 | 1 | 1 | 1 |
2核 | 2.12166984 | 2.29655239 | 2.06245262 |
4核 | 4.13682094 | 4.57633046 | 4.41327837 |
8核 | 4.46109479 | 5.23876108 | 4.1624517 |
2.3 图表
绘制成图表,如下图所示。
3. 实验分析
从实验结果和加速比可以看出:
- 随着矩阵的增大,串行和并行算法运行时间也在增大;
- Openmp并行程序可有效提高矩阵运行的速度;
- 在4核并行内,矩阵运行的加速比与核心数近似成正比;当并行线程数大于4后,矩阵运行的时间较4线程提升不大,实验中存在8个线程运行时间多于4线程的情况。
4. 源代码
#include <iostream>
#include "cstdlib"
#include "random"
#include "ctime"
#include "chrono"
#include "omp.h"
using namespace std;
using namespace std::chrono;
#define M 6000
#define N 6000
#define ThreadNumber 4
double matrix_a[M][N], matrix_b[N][M], result[M][M];
void init_matrix();
void serial_multiplication();
void parallel_multiplication();
int main() {
init_matrix();
auto start = system_clock::now();
serial_multiplication();
auto end = system_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "serial multiplication takes "
<< double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
start = system_clock::now();
parallel_multiplication();
end = system_clock::now();
duration = duration_cast<microseconds>(end - start);
cout << "parallel multiplication takes "
<< double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
return 0;
}
//generate the same matrix everytime
void init_matrix() {
default_random_engine engine;
uniform_real_distribution<double> u(0.0, 1.0);
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
matrix_a[i][j] = u(engine);
}
}
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
matrix_b[i][j] = u(engine);
}
}
}
void serial_multiplication() {
for (int i = 0; i < M; ++i) {
for (int j = 0; j < M; ++j) {
double temp = 0;
for (int k = 0; k < N; ++k) {
temp += matrix_a[i][k] * matrix_b[k][j];
}
result[i][j] = temp;
}
}
}
void parallel_multiplication() {
#pragma omp parallel for num_threads(ThreadNumber)
for (int i = 0; i < M; ++i) {
for (int j = 0; j < M; ++j) {
double temp = 0;
for (int k = 0; k < N; ++k) {
temp += matrix_a[i][k] * matrix_b[k][j];
}
result[i][j] = temp;
}
}
}