Constexpression's blog

并行编程实验

2023-06-24

并行编程实验

第1关:使用OpenMP进行并行矩阵乘法

OpenMP通过编译指导命令来并行化,什么是编译指导命令?简单来说就是我们平常写的#开头的语句,通过程序中插入的这些编译指导命令,计算机就会完成并行计算的工作。在C/C++程序中,OpenMP的所有的编译指导命令都是以#pragma omp开始的,后面跟具体的功能指导命令,命令形式如下:

1
#pragma omp 指令 子句,子句,子句……

parallel制导命令表示接下来由花括号括起来的区域将创建多个线程并行执行。可以用num_threads子句来控制线程的个数,如下:

1
2
3
4
5
6
7
8
9
10
11
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
#pragma omp parallel num_threads(5)
{

cout << "Hello, world!" << endl;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
omp_set_num_threads(2);
#pragma omp parallel
{

cout << "Hello, world!" << endl;
}
}

接下来将解锁一个常用的制导命令 for,直接将你的for循环体提升n倍!在并行域里面用以下命令,在这条语句之后的一个for循环语句中每一个要循环的任务将被分配给不同的线程去执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
omp_set_num_threads(2);
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<4;i++)
cout << omp_get_thread_num() << endl;
}
}

也可以直接把for写在parallel后面

1
#pragma omp parallel for

用schedule子句进行for循环任务调度的管理

1
schedule(type, size)

静态调度,不用size参数时分配给每个程序的都是n/t次连续迭代,n为迭代次数,t为并行的线程数目。

1
2
3
4
5
6
7
8
9
10
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
omp_set_num_threads(2);
#pragma omp parallel for schedule(static)
for(int i=0;i<8;i++)
cout << omp_get_thread_num() << endl;
}

使用size参数,表示每次分配给线程size次的连续迭代。

2.dynamic参数

动态调度模式是先到先得的方式进行任务分配,不用size参数的时候,先把任务干完的线程先取下一个任务,以此类推,而不是一开始就分配固定的任务数。使用size参数的时候,分配的任务以size为单位,一次性分配size个。虽然很智能,在任务难度不均衡的时候适合用dynamic,否则会引起过多的任务动态申请的开销。

3.guided参数

刚开始每个线程会分配到比较大的迭代块,后来分配到的迭代块逐渐递减,没有指定size就会降到1,否则降到size。

用sections把不同的区域交给不同的线程去执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<omp.h>
#include<iostream>
using namespace std;
int main()
{
omp_set_num_threads(3);
#pragma omp parallel sections
{
#pragma omp section
{
cout <<omp_get_thread_num();
}
#pragma omp section
{
cout << omp_get_thread_num();
}
#pragma omp section
{
cout << omp_get_thread_num();
}
}
}

输出:012

single制导指令所包含的代码段只有一个线程执行,别的线程跳过该代码,如果没有nowait子句,那么其他线程将会在single制导指令结束的隐式同步点等待。有nowait子句其他线程将跳过等待往下执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
omp_set_num_threads(4);
#pragma omp parallel
{
#pragma omp single
{
cout << "single thread=" << omp_get_thread_num()<<endl;
}
cout << omp_get_thread_num() << endl;
}

}
1
2
3
10
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章