1. MPI_Init(&argc, &argv);初始化,MPI_Finalize();结束
所有mpi函数在Init之后执行,但每个进程都会拥有整个代码,不只是两者之间的代码,每个进程都会有变量的私有备份。
2. MPI_Comm_size(MPI_COMM_WORLD, &nproces);总进程数
MPI_Comm_rank(MPI_COMM_WORLD, &rank);当前进程
3. MPI_Wtime();获取时间,浮点数
4. MPI_Get_processor_name(name, &len); 获取当前主机,len为长度
5. MPI_Get_version(&a, &b);获取mpi主版本次版本号
6. MPI_Send(buf, 2, MPI_INT, i, 1, MPI_COMM_WORLD);
MPI_Recv(buf, 2, MPI_INT, i, 1, MPI_COMM_WORLD, &status);
Send 发送之后,如果对相同进程发送数据,形成缓冲区,不会覆盖前面一个,Recv会一个一个的接收。
7. MPI_STATUS 有 MPI_TAG MPI_SOURCE MPI_ERROR
8. MPI_Barrier(MPI_COMM_WORLD);等待进程同步
9. MPI_ANY_SOURCE //任意源 MPI_ANY_TAG //任意tag
10. Jacobi迭代(对等模式mpi并行化)
左右两边都保留一列,
遇到的问题:边界处理,所有第0行最后一行赋值为8,左边第1列为8,右边第my_size为8,左边第0列留空,右边第my_size+1留空,这地方在最后计算时注意边界处理。0进程从2开始到my_size,3进程从1开始到my_size-1。
1. MPI_Sendrecv(t, totalsize, MPI_DOUBLE, rank+1, 1, t, totalsize, MPI_DOUBLE, rank+1, 0, MPI_COMM_WORLD, &status); 将send和recv整合,这个函数比分开写号,系统会优化进程通信避免死锁。
2. MPI_Sendrecv_replace(t, totalsize, MPI_DOUBLE, rank+1, 1, rank+1,0,MPI_COMM_WORLD, &status); 因为发送和接收都一样大小并且类型一样,共用缓冲区。
3. MPI_PROC_NULL 值为-1,虚拟进程,向这个进程发送接收数据时,会返回真,执行一个空操作,简化代码,减少边界操作。
4. 矩阵向量乘(主从模式并行)
a[4][4] b[4]
行分解:将a按行分为几块,比如当前进程数为3,将a分为2块,给进程1,2;0号进程负责广播和输出。
1负责1.2行,2负责34行或者 1负责 1 3行,2负责24行。
两种不同的分配方法,一种是顺序分配一种是取余分配。
a的第一行乘以b得c的第一个值。每一行都要乘以b,所以对于每个进程来说,b是共享的。用MPI_Bcast将b广播给所有进程。计算结果要返回给0进程。每一行计算完都返回给0进程,将每一个MPI_Send 的tag设置为当前行数,0进程接收到时根据status取出tag,便于对c的赋值。
1. 列分解(未实现)
a的每一列乘以b,b依然是共享的,a[0][0] * b[0] 得到 c[0] 的一部分,a[0][1]*b[0]的c[0]的第二部分,第一个进程得到每个c的两部分,每个进程发送时发送一个temp数组即可包含了c的部分值,将每个进程的c加和得到最终的C。
1. 矩阵乘
行分解类似矩阵向量乘,b依然是共享的,每个进程发送时,发送的是矩阵c的一行,并且tag依然代表了计算的行。
列分解(未实现)得到的是矩阵c所有值的一部分,每个进程对c的每个值加和可得c,似乎好实现。
块分解(未实现)将a行分解,b列分解,进程中的a和b相乘的c[i][j]。。。等等,计算完之后将b发给其他进程,迭代,这样每个进程都可以得到完整的b。