最近入了并行计算的坑,也是因为这学期有一门这样的课。但是还没开始上就自己瞎看书。昨天下午开始配mpi,一开始想弄到clion里面,但是相关的资料太少了,遂卒。老老实实弄到了vs里面(虽然他很大很丑但是做这种事还是蛮方便)。但是今天早上打开越看越丑,难以接受,就跑到Ubuntu上面搞clion。目前依旧卒着,看看明天有心情继续配吧,今天先用vs跑一跑简单例子。
具体配置过程就不说了,vs上的有一大堆。
#include <stdio.h>
#include <string.h>
#include <mpi.h>
const int MAX_STRING = 100;
int main() {
char greeting[MAX_STRING];
int comm_sz;
int my_rank;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if (my_rank != 0) {
sprintf(greeting, "Greeting from process %d of %d!", my_rank, comm_sz);
MPI_Send(greeting, strlen(greeting) + 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
}
else {
printf("I am the boos! (%d)\n", my_rank);
for (int q = 1; q < comm_sz; ++q) {
MPI_Recv(greeting, MAX_STRING, MPI_CHAR, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
printf("%s\n", greeting);
}
}
MPI_Finalize();
return 0;
}
简单做一下笔记,mpi就是消息传递接口的意思,简单来说就是开好几个进程,各自干各自的事情,然后定义了一套消息交流的方案,就实现了比较简单的并行。
程序一开始进行初始化,一个作用就是定义了由用户启动的所有进程所组成的通信子。然后两个函数声明了总的进程数量和自己的rank。
然后就是比较重要的通信了,两个函数
MPI_Send(sned_p,sned_size,type,to,tag,comm)
MPI_Recv(recv_p,recv_size,type,from,tag,comm,&status)
分别表示发送(接收)内容的起始位置,大小,传递的数据类型,发给谁(从谁那里收到),标记,通信子,(发送者信息)。
然后是一点应用:求函数的定积分(这里找的函数是2x^3-10*x^2+100)
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#define db double
const db dir = 1e-7;
int comm_sz;
int my_rank;
db l, r, d;
db F(db x) {
return 2 * x * x * x - 10 * x * x + 100;
}
db Cal(db L, db R) {
db res = 0;
for (db i = L; i <= R - dir; i += dir)
res += (F(i) + F(i + dir));
return res * dir / 2;
}int main() {
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
l = 0; r = 50;
d = (r - l) / comm_sz;
db L = l + d * my_rank, R = l + d * (my_rank + 1.0);
db S = Cal(L, R);
db ans = S;
if (my_rank != 0) {
MPI_Send(&S, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
}
else {
for (int q = 1; q < comm_sz; ++q) {
MPI_Recv(&S, 1, MPI_DOUBLE, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
ans += S;
}
printf("The totle area is %.5f\n", ans);
}
MPI_Finalize();
return 0;
}
自己瞎写的矩阵乘优化,开4个进程大约提速3倍的样子,但是空间浪费了不少,感觉还能优化好多好多,先沾上吧,去看看书上怎么写的。
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include <math.h>
#define maxn 5010
#define db double
const db dir = 1e-5;
int comm_sz;
int my_rank;
int n, a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], d;
int min(int x, int y) {
return x < y ? x : y;
}
void Cal(int l, int r, int size, int ans[maxn * maxn]) {
if (l > r)return;
//printf("%d %d\n", l, r);
for (int k = 0; k < n; k++)
for (int i = 0; i < size; i++)
for (int j = 0; j < n; j++) {
ans[i * n + j] += a[i + l][k] * b[k][j];
}
}
int res[maxn*maxn], ans[maxn][maxn];
int main() {
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
n = 2000;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[i][j] = (i * 100 + j * 10) % 233;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
b[i][j] = (i * 100 + j * 10) % 233;
d = ceil(n * 1.0 / comm_sz);
int l = my_rank * d;
int r = min(n - 1, l + d - 1);
int size = r - l + 1;
for (int i = 0; i < size; i++)
for (int j = 0; j < n; j++)
res[i * n + j] = 0;
Cal(l, r, size, res);
if (my_rank != 0) {
if(size>0)MPI_Send(res, size * n, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
else {
int l, r, size, now = 0;
l = 0; r = min(n - 1, d - 1);
for (int i = l; i <= r; i++)
for (int j = 0; j < n; j++) {
ans[i][j] = res[now]; now++;
}
for (int q = 1; q < comm_sz; ++q) {
l = q * d;
r = min(n - 1, l + d - 1);
if (l > r)break;
size = r - l + 1;
MPI_Recv(res, size * n, MPI_INT, q, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
now = 0;
for (int i = l; i <= r; i++)
for (int j = 0; j < n; j++) {
ans[i][j] = res[now]; now++;
}
}
printf("ok\n");
for (int i = 0; i < n; i++)
printf("%d\n", ans[0][i]);
/*
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
printf("%d ", ans[i][j]);
printf("\n");
}*/
}
MPI_Finalize();
return 0;
}