mpi学习记录

mpi简介

  1. mpi是一个库,不是一个语言,可以在FORTRAN和C的基础上进行开发,他遵守对库函数的调用规则
  2. mpi是一个标准的规范,一个正确的mpi函数可以在任何一台并行机上运行
  3. mpi是一种消息传递编程模型,其最终目的是服务于进程间通信这一目的

mpi常用函数调用

1. MPI_Init(&argc,&argv)

是MPI程序的第一个调用,初始化MPI执行环境。必须在每个MPI程序中调用此函数,必须在任何其他MPI函数之前调用此函数,并且在MPI程序中只能调用一次。对于C程序,MPI_Init可以用于将命令行参数传递给所有进程,这不是标准要求的,取决于实际。

2.MPI_Finalize()

是MPI程序的最后一个调用,终止MPI执行环境。此函数应该是每个MPI程序中最后一个调用的MPI例程-此后不得再调用其他MPI例程。

3. MPI_Comm_rank(comm,&rank)

IN comm 该进程所在的通信域(句柄)一般为MPI_COMM_WORLD
OUT rank 所调用进程在comm中的标识号id

返回指定通信器中调用MPI进程的编号。最初,在通信域MPI_COMM_WORLD中,将为每个进程分配 一个介于0和(任务数-1)之间的唯一整数等级。该等级通常称为任务ID。如果某个过程与其他沟通者相关联,则在每个沟通者中也将具有唯一的id,有了这一编号就可以将这一进程于其他分割开来,实现各进程的并行和协作。

4.MPI_Comm_size(comm,&size)

IN comm 通行域(句柄)
OUT size 通信域comm中所包含的进程数

返回指定通信器中MPI进程的总数,例如MPI_COMM_WORLD。如果通信器是MPI_COMM_WORLD,则它表示可用于您的应用程序的MPI任务数。

5.MPI_Get_processor_name (&name,&resultlength)

返回处理器名称,还返回名称的长度。“名称”的缓冲区的大小必须至少为MPI_MAX_PROCESSOR_NAME个字符。返回到“名称”中的是与实现相关的-可能与“主机名”或“主机” shell命令的输出不同。

#include "mpi.h" 
#include <stdio.h> 
#include <math.h> 
#include<Windows.h>
#include <iostream> 
using namespace std;
int main(int argc, char* argv[]) {
    int myid; // 当前进程的编号 
    int numprocs; // 当前进程的名称 
    int namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(&argc, &argv);//mpi程序开始
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);//返回进程id
    MPI_Get_processor_name(processor_name, &namelen);//返回处理器名称和名称长度
    cout  << processor_name << namelen << endl;
    int i;
    for (i = 0; i < 4; ++i) {
        cout << "I'm" << myid << ", sending " << i << endl;
        Sleep(1);
        if (0 == myid && 0 == i) {
            MPI_Barrier(MPI_COMM_WORLD); //进程0将一直等待,直到其他并行进程执行结束 
        }
    }
    //MPI_Finalize(); //由于未执行MPI_Finalize,进程0无法感知到其他进程已退出 
    return 0;
}

6.MPI_Send (&buf,count,datatype,dest,tag,comm) (阻止发送)

IN buf 发送内容缓冲区的起始地址
IN count 将要发送的数据的个数(非负整数)
IN datatype 发送消息的数据类型(句柄)
IN dest 目标进程的标识(整型)
IN tag 消息标志(整型)
IN comm 通信域(句柄)

MPI_Send将发送缓冲区中的count个datatype数据类型的数据发送到目的进程目的进
程在通信域中的标识号是dest 本次发送的消息标志是tag 使用这一标志就可以把本次发
送的消息和本进程向同一目的进程发送的其它消息区别开来
MPI_Send操作指定的发送缓冲区是由count个类型为datatype的连续数据空间组成起
始地址为buf 注意这里不是以字节计数而是以数据类型为单位指定消息的长度这样就
独立于具体的实现并且更接近于用户的观点

7.MPI_Isend(&buf,count,datatype,dest,tag,comm,request) (非阻塞发送)

IN buf 发送内容缓冲区的起始地址
IN count 将要发送的数据的个数(非负整数)
IN datatype 发送消息的数据类型(句柄)
IN dest 目标进程的标识(整型)
IN tag 消息标志(整型)
IN comm 通信域(句柄)
OUT request 返回状态 (状态类型)
(可以任意定义一个MPI_Status变量来接收返回值)

8.MPI_Recv (&buf,count,datatype,source,tag,comm,&status) (阻止接收)

OUT buf 接收缓冲区的起始地址(可选数据类型)
IN count 最多可接收的数据的个数(整型)
IN datatype 接收数据的数据类型(句柄)
IN source 接收数据的来源即发送数据的进程的进程标识号(整型)
IN tag 消息标识与相应的发送操作的表示相匹配相同(整型)
IN comm 本进程和发送进程所在的通信域(句柄)
OUT status 返回状态 (状态类型)

MPI_Recv从指定的进程source接收消息并且该消息的数据类型和消息标识和本接收
进程指定的datatype和tag相一致接收到的消息所包含的数据元素的个数最多不能超过
count
接收缓冲区是由count个类型为datatype的连续元素空间组成由datatype指定其类型起
始地址为buf 接收到消息的长度必须小于或等于接收缓冲区的长度这是因为如果接收到
的数据过大MPI没有截断接收缓冲区会发生溢出错误因此编程者要保证接收缓冲区的
长度不小于发送数据的长度如果一个短于接收缓冲区的消息到达那么只有相应于这个消
息的那些地址被修改count可以是零这种情况下消息的数据部分是空的
(可以任意定义一个MPI_Status变量来接收返回值)

9.MPI_IRecv(&buf,count,datatype,source,tag,comm,requst) (非阻塞接收)

OUT buf 接收缓冲区的起始地址(可选数据类型)
IN count 最多可接收的数据的个数(整型)
IN datatype 接收数据的数据类型(句柄)
IN source 接收数据的来源即发送数据的进程的进程标识号(整型)
IN tag 消息标识与相应的发送操作的表示相匹配相同(整型)
IN comm 本进程和发送进程所在的通信域(句柄)
OUT requst 返回状态 (状态类型)

#include<iostream>
#include"mpi.h"
using namespace std;
int main(int arge, char* argv[]) {
    char message[20];
    int myrank;
    MPI_Status status;
    MPI_Init(&arge, &argv);//程序开始
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);//返回进程id
    if (myrank == 0) {
        strcpy_s(message, "hello, process i");
        MPI_Send(message, strlen(message), MPI_CHAR, 1, 99, MPI_COMM_WORLD);//从0号进程发送消息到一号进程
    }
    else {
        if (myrank == 1) {
            MPI_Recv(message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);//接收消息
            printf("%s", message);
        }
        MPI_Finalize();//程序结束
    }
}
#include "stdio.h"
#include "mpi.h"
#include<string.h>
#include<math.h>
#include<cstdlib>
#include "stdlib.h"
int main(int argc, char** argv)
{
	int rank, size;
	MPI_Request r1, r2;
	MPI_Status s;
	int buf[10000], buf2[10000], count, tag1, tag2;
	count = 10000;
	tag1 = 100;
	tag2 = 1000;
	MPI_Init(&argc, &argv);
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &size);
	if (rank == 0) {
		MPI_Isend(buf, count, MPI_INT, 1, tag1, MPI_COMM_WORLD, &r1);
		MPI_Isend(buf2, count, MPI_INT, 1, tag2, MPI_COMM_WORLD, &r2);
		MPI_Wait(&r1, &s);
		MPI_Wait(&r2, &s);
	}
	else
		if (rank == 1) {
			MPI_Irecv(buf2, count, MPI_INT, 0, tag2, MPI_COMM_WORLD, &r2);
			MPI_Irecv(buf, count, MPI_INT, 0, tag1, MPI_COMM_WORLD, &r1);
			MPI_Wait(&r2, &s);
			if (s.MPI_TAG != tag2) {
				printf("error in receive order\n");
			}
			MPI_Wait(&r1, &s);
		}
	MPI_Barrier(MPI_COMM_WORLD);
	if (rank == 0) {
		printf("test completed\n");
	}
	MPI_Finalize();
	return 0;
}

MPI预定义数据类型

MPI预定义数据类型相应的c语言数据类型
MPI_CHARsigned char
MPI_SHARTsigned short int
MPI_INTsigned int
MPI_LONGsigned long int
MPI_UNSIGNED_CHARunsigned char
MPI_UNSIGNED_SHORTunsigned shortint
MPI_UNSIGNEDunsigned int
MPI_UNSIGNED_LONGunsigned long int
MPI_FLOATfloat
MPI_DOUBLEdouble

mpi中严格要求类型的匹配,所以在mpi中不存在数据类型的转换
在这里插入图片描述

MPI的消息传递过程可以分为三个阶段
1.消息装配将发送数据从发送缓冲区中取出加上消息信封等形成一个完整的消息
2.消息传递将装配好的消息从发送端传递到接收端
3.消息拆卸从接收到的消息中取出数据送入接收缓冲区
在这三个阶段都需要类型匹配在消息装配时发送缓冲区中变量的类型必须和相
应的发送操作指定的类型相匹配‚在消息传递时发送操作指定的类型必须和相应的接收
操作指定的类型相互匹配ƒ在消息拆卸时接收缓冲区中变量的类型必须和接收操作指定
的类型相匹配

mpi通信

MPI消息包括信封和数据两个部分 信封指出了发送或接收消息的对象及相关信息而
数据是本消息将要传递的内容信封和数据又分别包括三个部分可以用一个三元组来表示
信封<源/目标识通信域>
数据<起始地址数据个数数据类型>
在这里插入图片描述
在这里插入图片描述
一个接收操作对消息的选择是由消息的信封管理的。如果消息的信封与接收操作所指定的值source,tag和comm相匹配,那么这个接收操作能接收这个消息。
接收者可以给source指定一个任意MPI_ANY_SOURCE 标识任何进程发送的消息都可以接收,即本接收操作可以匹配任何进程发送的消息但其它的要求还必须满足比如tag的匹配。
如果给tag一个任意值MPI_ANY_TAG 则任何tag都是可接收的。
一个接收操作可以接收任何发送者的消息但是对于一个发送操作则必须指明一个单独的接收者

同步/阻止消息传递

在这里插入图片描述
阻止发送 MPI_Send(buffer,count,type,dest,tag,comm)
阻止接收 MPI_Recv(buffer,count,type,source,tag,comm,status)

异步/非阻塞消息传递

在这里插入图片描述
非阻止发送 MPI_ISend(buffer,count,type,dest,tag,comm,request)
非阻止接收 MPI_IRecv(buffer,count,type,source,tag,comm,requst)
注:在非阻塞通信中一般使用

MPI_Wait(request, status)

阻止,直到操作实际完成

INOUT request 请求(句柄)  
OUT status 状态对象(状态类型)

MPI_Test(request, flag, status)

返回一个标志判断

INOUT request 通信请求(句柄)  
OUT flag 如果操作完成则为真(逻辑型)  
OUT status 状态对象(状态类型)

简单mpi程序

mpi实现计时功能

MPI_Wtime()

返回调用处理器上经过的挂钟时间,以秒为单位(双精度)。

double starttime,endtime;

starttime=MPI_Wtime();
需计时部分代码
endtimr=MPI_Wtime();
printf("%f",endtime-starttime);

#include<iostream>
#include"mpi.h"
#include<Windows.h>
using namespace std;
int main(int argc, char* argv[]) {
    int err = 0;
    double t1, t2;
    int i;
    MPI_Init(&argc, &argv);
    t1 = MPI_Wtime();
    t2 = MPI_Wtime();
    if (t2 - t1 > 0.1 || t2 - t1 < 0.0) {
        //若两个连续调用的时间函数时间差距大于0.1秒或者后面的时间函数比先调用的小则时间调用错误
        err++;
        cout << t1 << "     " << t2 << endl;
    }
    for ( i = 0; i < 10; i++) {
        t1 = MPI_Wtime();
        Sleep(1000);
        t2 = MPI_Wtime();
        if (t2 - t1 >= (1.0 - 0.01) && t2 - t1 <= 5.0)break;
        else i = 9;
    }
    if (i == 10) {
        err++;
        cout << t2 - t1 << endl;
    }
    MPI_Finalize();
}

是否初始化及错误退出

MPI_Initialized(&flag)

指示是否已调用MPI_Init-将标志返回为逻辑true(1)或false(0)。MPI要求每个进程仅一次调用MPI_Init。MPI_Initialized判断MPI_Init是否已经执行。

OUT flag MPI_Init是否执行的标志

MPI_Abort (comm,errorcode) 终止与comm关联的所有MPI进程。在大多数MPI实现中,无论指定哪个通信器,它都会终止所有进程,并且不要求外部环境对错误码采取任何动作

IN comm 退出进程所在的通信域
IN errorcode 返回到所嵌环境的错误码

MPI_Barrier(comm)

用于一个通信子中所有进程的同步,调用函数时进程将处于等待状态,直到通信子中所有进程 都调用了该函数后才继续执行。

数据的接力传输

#include <stdio.h>
#include "mpi.h"
int main(int argc,char* argv[])
{
    int rank, value, size;
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    printf("%d", size);
    /* 得到当前进程标识和总的进程个数*/
    do {
        /* 循环执行 直到输入的数据为负时才退出*/
        if (rank == 0) {
            fprintf(stderr, "\nPlease give new value=");
            /*进程0读入要传递的数据*/
            scanf_s("%d", &value);
            fprintf(stderr, "%d read <-<- (%d)\n", rank, value);
            if (size > 1) {
                MPI_Send(&value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD);
                fprintf(stderr, "%d send (%d)->-> %d\n",
                    rank, value, rank + 1);
                /* 若不少于一个进程则向下一个进程传递该数据*/
            }
        }
        else {
            MPI_Recv(&value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,
                &status);
            /* 其它进程从前一个进程接收传递过来的数据*/
            fprintf(stderr, "%d receive (%d)<-<- %d\n", rank, value, rank - 1);
            if (rank < size - 1) {
                MPI_Send(&value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD);
                fprintf(stderr, "%d send (%d)->-> %d\n",
                    rank, value, rank + 1);
                /*若当前进程不是最后一个进程则将该数据继续向后传递*/
            }
        }
        MPI_Barrier(MPI_COMM_WORLD);
        /* 执行一下同步 加入它主要是为了将前后两次数据传递分开*/
    } while (value >= 0);
    MPI_Finalize();
}

任意源和任意标识的使用

#include "mpi.h"
#include <stdio.h>
int main(int argc,char* argv[])
{
    int rank, size, i, buf[1];
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    if (rank == 0) {
        for (i = 0; i < 100 * (size - 1); i++) {
            MPI_Recv(buf, 1, MPI_INT, MPI_ANY_SOURCE,
                MPI_ANY_TAG, MPI_COMM_WORLD, &status);
            printf("Msg=%d from %d with tag %d\n",
                buf[0], status.MPI_SOURCE, status.MPI_TAG);
        }
    }
    else {
        for (i = 0; i < 100; i++)
            buf[0] = rank + i;
        MPI_Send(buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD);
    }
    MPI_Finalize();
}

安全的mpi程序

错误的死锁现象

在这里插入图片描述

不安全的通讯次序

在这里插入图片描述

安全的通讯次序

在这里插入图片描述

信息的捆绑式发送与接收

MPI_SENDRECV(sendbuf,sendcount,sendtype,dest,sendtag,recvbuf,recvcount,recvtype,source,recvtag,comm,status)

IN sendbuf 发送缓冲区起始地址(可选数据类型)
IN sendcount 发送数据的个数(整型)
IN sendtype 发送数据的数据类型(句柄)
IN dest 目标进程标识(整型)
IN sendtag 发送消息标识(整型)
OUT recvbuf 接收缓冲区初始地址(可选数据类型)
IN recvcount 最大接收数据个数(整型)
IN recvtype 接收数据的数据类型(句柄)
IN source 源进程标识(整型)
IN recvtag 接收消息标识(整型)
IN comm 通信域(句柄)
OUT status 返回的状态(status)

捆绑发送和接收操作把发送一个消息到一个目的地和从另一个进程接收一个消息合并到
一个调用中源和目的可以是相同的捆绑发送接收操作虽然在语义上等同于一个发送操作
和一个接收操作的结合但是它可以有效地避免由于单独书写发送或接收操作时由于次序
的错误而造成的死锁这是因为该操作由通信系统来实现系统会优化通信次序从而有效
地避免不合理的通信次序最大限度避免死锁的产生

MPI_SENDRECV_REPLACE(buf,count,datatype,dest,sendtag,source,recvtag,comm, status)

INOUT buf 发送和接收缓冲区初始地址(可选数据类型)
IN count 发送和接收缓冲区中的数据的个数(整型)
IN datatype 发送和接收缓冲区中数据的数据类型(句柄)
IN dest 目标进程标识(整型)
IN sendtag 发送消息标识(整型)
IN source 源进程标识(整型)
IN recvtag 接收消息标识(整型)
IN comm 发送进程和接收进程所在的通信域(句柄)
OUT status 状态目标(status)

一个与MPI_SENDRECV 类似的操作是MPI_SENDRECV_REPLACE 它与
MPI_SENDRECV的不同就在于它只有一个缓冲区该缓冲区同时作为发送缓冲区和接收缓
冲区这一调用的执行结果是发送前缓冲区中的数据被传递给指定的目的进程该缓冲区被
从指定进程接收到的相应类型的数据所取代因此从功能上说这两者没有什么区别只是
MPI_SENDRECV_REPLACE相对于MPI_SENDRECV节省了一个接收缓冲区和发送缓冲
区公用

集体沟通

MPI_Barrier(comm)

同步操作。在组中创建障碍同步。每个任务在到达MPI_Barrier调用时都会阻塞,直到组中的所有任务都到达相同的MPI_Barrier调用。然后,所有任务都可以自由进行

MPI_Bcats(buffer,count,datatype,root,comm)

IN/OUT buffer    通信消息缓冲区的起始地址(可变)
IN    count     通信消息缓冲区中的数据个数(整型) 
IN    datatype  通信消息缓冲区中的数据类型(句柄) 
IN    root     发送广播的根的序列号(整型) 
IN    comm     通信域(句柄)

从一个序列号为root的进程将一条消息广播发送到组内的所有进程,包括它本身在内.调用时组内所有成员都使用同一个comm和root,其结果是将根的通信消息缓冲区中的消息拷贝到其他所有进程中去.
在这里插入图片描述
在这里插入图片描述

MPI_Scatter(&sendbuf,sendcnt,sendtype,&recvbuf,recvcnt,recvtype,root,comm)

IN sendbuf 发送消息缓冲区的起始地址(可变,仅对于根进程)
IN sendcount 发送到各个进程的数据个数(整型,仅对于根进程)
IN sendtype 发送消息缓冲区中的数据类型(句柄,仅对于根进程)
OUT recvbuf 接收消息缓冲区的起始地址(可变)
IN recvcount 待接收的元素个数(整型)
IN recvtype 接收元素的数据类型(句柄)
IN root 发送进程的序列号(整型)
IN comm 通信子(句柄)

通过根进程向同一个通信域中的所有进程发送数据,将数据发送缓冲区的数据分割成长度相等的段,然后分段发送数据给每个进程,如果每段包含N个数据,则向进程i发送的段为[send[iN],int[iN+N])
在这里插入图片描述
在这里插入图片描述

MPI_Gather(&sendbuf,sendcnt,sendtype,&recvbuf, recvcount,recvtype,root,comm)

IN sendbuf   发送消息缓冲区的起始地址(可变)   
IN sendcount  发送消息缓冲区中的数据个数(整型)   
IN sendtype  发送消息缓冲区中的数据类型(句柄)  
OUT recvbuf   接收消息缓冲区的起始地址(可变,仅对于根进程)   
IN recvcount 待接收的元素个数(整型,仅对于根进程)   
IN recvtype   接收元素的数据类型(句柄,仅对于根进程)   
IN root    接收进程的序列号(整型)   
IN comm    通信子(句柄)

数据移动操作。收集从组中每个任务到单个目标任务的不同消息。此例程是MPI_Scatter的反向操作。每个进程(包括根进程)将其发送缓冲区中的内容发送到根进程,根进程根据发送这些数据的进程的序列号将它们依次存放到自已的消息缓冲区中.其结果就象一个组中的n个进程(包括根进程在内)都执行了一个调用:
在这里插入图片描述
在这里插入图片描述

#include "stdio.h"
#include "mpi.h"
#include "stdlib.h"

int main(int argc, char** argv)
{
    int size, rank;
    static int max = 20;
    int send[10];
    int* recv=NULL;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    for (int i = 0; i < 10; i++)
        send[i] = i + rank;

    if (rank == 0)
    {
        recv = (int*)malloc(size * 10 * sizeof(int));
    }
    MPI_Gather(send, 10, MPI_INT, recv, 10, MPI_INT, 0, MPI_COMM_WORLD);
    if (rank == 0)
    {
        for (int i = 0; i < size * 10; i++)
            printf("%d\n", recv[i]);
    }

    MPI_Finalize();
    return 0;
}

MPI_Allgather(&sendbuf,sendcount,sendtype,&recvbuf, recvcount,recvtype,comm)

IN sendbuf   发送消息缓冲区的起始地址(可变)   
IN sendcount  发送消息缓冲区中的数据个数(整型)   
IN sendtype  发送消息缓冲区中的数据类型(句柄)  
OUT recvbuf   接收消息缓冲区的起始地址(可变,仅对于根进程)   
IN recvcount 待接收的元素个数(整型,仅对于根进程)   
IN recvtype   接收元素的数据类型(句柄,仅对于根进程)    
IN comm    通信子(句柄)

数据移动操作。将数据串联到组中的所有任务。实际上,组中的每个任务在组内执行一对一广播操作。
在这里插入图片描述
在这里插入图片描述

MPI_Reduce (&sendbuf,&recvbuf,count,datatype,op,root,comm)

IN sendbuf 发送消息缓冲区的起始地址(可变)
OUT recvbuf 接收消息缓冲区中的地址(可变,仅对于根进程)
IN count 发送消息缓冲区中的数据个数(整型)
IN datatype 发送消息缓冲区的元素类型(句柄)
IN op 归约操作符(句柄)
IN root 根进程序列号(整型)
IN comm 通信子(句柄)

集体计算操作。对组中的所有任务应用归约运算,并将结果放在一个任务中。
在这里插入图片描述

在这里插入图片描述

MPI_MAX最大值
MPI_MIN最小值
MPI_SUM求和
MPI_PROD求积
MPI_LAND逻辑与
MPI_BAND按位与
MPI_LOR逻辑或
MPI_BOR按位或

MPI_Allreduce (&sendbuf,&recvbuf,count,datatype,op,comm)

IN sendbuf 发送消息缓冲区的起始地址(可变)
OUT recvbuf 接收消息缓冲区中的地址(可变,仅对于根进程)
IN count 发送消息缓冲区中的数据个数(整型)
IN datatype 发送消息缓冲区的元素类型(句柄)
IN op 归约操作符(句柄)
IN comm 通信子(句柄)

与MPI_Allgather对MPI_Gather的补充类似,MPI_Allreduce进行规约并将结果分发给所有进程
在这里插入图片描述

在这里插入图片描述

组和通信器管理例程

 MPI_Group
 MPI_Comm

MPI_Comm_group(Comm, &Group)

使用MPI_Comm_group从MPI_COMM_WORLD中提取全局组的句柄, 访问与给定通信器关联的组

MPI_Group_incl(Group, size, &ranks, &NewGroup)

使用MPI_Group_incl将新组作为全局组的子集, 通过包括现有组中的成员子集 生成组

MPI_Comm_create(Comm, Group, &NewComm)

使用MPI_Comm_create为新组创建新的传播者,创建新的沟通者新的通信器必须是原始组的子 集

完成后,使用MPI_Comm_free和MPI_Group_free释放新的通信器和组

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值