MPI 奇偶排序

编译:mpicc -o 目标文件 源文件.cpp
运行:mpirun -n 进程数 -machinefile ./machinefile ./目标文件

带注释版(但是有点小的语法错误)


#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>//exit 
#include <malloc.h>
#include <memory.h>
#include <time.h>
void merge(int mykeys[], int receive[], int n, int flag);
void odd_even_sort(int a[], int n);
void doSort(int myid, int local_n, int np);
void printMatrix(int array[], int n);
void init(int n, int myid, int np);
int getPartner(int phase, int myid, int comm_sz);
int cmp(const void *a, const void *b);
int *array, *mykeys, *receive;
int n, partner;
void Get_input(int my_rank , int comm_sz, int * n_p) {
    int dest ;
    if(my_rank ==0) {
        printf("Enter  n\n");
        scanf("%d", n_p);
        for(dest =1 ;dest < comm_sz;dest++) {
            MPI_Send(n_p,1,MPI_INT, dest,0, MPI_COMM_WORLD);
        }
    }
    else {
        MPI_Recv(n_p, 1 ,MPI_INT,0,0,MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }
}
void merge(int mykeys[], int receive[], int n, int flag)
{
    int mi, ti, ri; //mykeys receive的数目 
    int *temp = malloc(sizeof(int) * n * 2); //n 为local_n ,将两个进程的数合并 
    if (temp == NULL)
    {
        exit(-1);//非正常运行退出  
    }
    mi = ri = ti = 0;
    while (mi < n && ri < n)
    {
        if (mykeys[mi] >= receive[ri])
        {
            temp[ti] = receive[ri];
            ri++;
            ti++;
        }
        else
        {
            temp[ti] = mykeys[mi];
            ti++;
            mi++;
        }
    }
    while (mi < n)
    {
        temp[ti] = mykeys[mi];
        ti++;
        mi++;
    }
    while (ri < n)
    {
        temp[ti] = receive[ri];
        ti++;
        ri++;
    }
    ti = flag > 0 ? n : 0;
    
    for (mi = 0; mi < n; mi++)
        mykeys[mi] = temp[ti++];
        
    free(temp);
}
void printMatrix(int array[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        printf("%d\n", array[i]);
}
void doSort(int myid, int local_n, int np)   4. 进行np轮排序。 
{
    int i;
    for (i = 0; i < np; i++)
    {
        partner = getPartner(i, myid, np);
        if (partner != MPI_PROC_NULL) // 不是空进程 
        {
            MPI_Sendrecv(mykeys, local_n, MPI_INT, partner, 0, receive, local_n, MPI_INT, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            merge(mykeys, receive, local_n, myid - partner);
        }
    }//接受和发送消息标签都为0 
}
//进程间的通信需要通过一个通信器来完成。MPI 环境在初始化时会自动创建两个通信器,一个称为 MPI_COMM_WORLD,它包含程序中的所有进程
// MPI_COMM_SELF,它是每个进程独自构成的、仅包含自己的通信器。
//MPI 系统提供了一个特殊进程号 MPI_PROC_NULL,它代表空进程 (不存在的进程),
//与 MPI_PROC_NULL 进行通信相当于一个空操作,对程序的运行没有任何影响。 
//若单纯的利用MPI_Send, MPI_Recv函数进行通讯的话,容易造成死锁,下面介绍MPI_Sendrecv的来解决这个问题。
//MPI_Sendrecv表示的作用是将本进程的信息发送出去,并接收其他进程的信息
//MPI_Send和MPI_Recv两个函数是MPI里基本的点对点通信例程。
//两个函数都会阻塞调用进程,直到通信操作完成。阻塞可能会造成死锁。
void init(int n, int myid, int np)
{
    int i;
    int total = n + np - n % np;  //一共有多少个数(填充后) 
 //其中有不能整除问题,对于不能整除的进行填补,
 //用最大的数填充数组最后几个元素使之能整除 
    if (!myid) //如果不是0进程 
    {
        srand(time(NULL));
        //srand( (time(NULL) )中time(NULL)函数是得到一个从1900年1月1日到现在的时间秒数
  //这样每一次运行程序的时间的不同就可以保证得到不同的随机数了。 
        array = (int *)malloc(sizeof(int) * total);
        for (i = 0; i < n; i++)
        {
            *(array + i) = random();
        }
        for (i = n; i < total; i++)
        {
            *(array + i) = 0x7fffffff; //数组元素大小不能超过 0x7fffffff
        }
    }
    receive = (int *)malloc(sizeof(int) * total / np);
    mykeys = (int *)malloc(sizeof(int) * total / np);
}
int getPartner(int phase, int myid, int comm_sz)  //partner = getPartner(i, myid, np); 
{
    int partner;
    //phase为第几轮,先从偶排序开始 
    if (phase % 2 == 0)
    {
        if (myid % 2 != 0)
        {
            partner = myid - 1;
        }
        else
        {
            partner = myid + 1;  01 23 
        }
    }
    else
    {
        if (myid % 2 != 0)
        {
            partner = myid + 1;
        }
        else
        {
            partner = myid - 1;
        }
    }
    if (partner == -1 || partner == comm_sz)
    {
        partner = MPI_PROC_NULL;
    }
    return partner;
}
int cmp(const void *a, const void *b)   //第一步:自己内部排序 
{
    return *((int *)a) > *((int *)b);
}
int main(void) //int argc, char **argv
{
    int i, j;
    int myid, np, namelen; // np is size numprocess
    char proc_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &np);
    MPI_Get_processor_name(proc_name, &namelen);
    double beginTime, endTime;
    beginTime = MPI_Wtime();  
    Get_input(myid, np,  &n);
   // n = atoi(argv[1]);  //atoi()代表的是ascii to integer,即“把字符串转换成有符号数字” 
    int local_n = (n + (np - n % np)) / np; // 填充  矩阵 
    //其中有不能整除问题,对于不能整除的进行填补,
 //用最大的数填充数组最后几个元素使之能整除  
    //初始化随机数。
    init(n, myid, np);
    // 2. 把数据广播出去。
//int array[] = {15, 11, 9, 16, 3, 14, 8, 7, 4, 6, 12, 10, 5, 2, 13, 1};
    MPI_Scatter(array, local_n, MPI_INT, mykeys, local_n, MPI_INT, 0, MPI_COMM_WORLD); //mykey为接受缓冲区起始地址 
    // 3. local sort
    qsort(mykeys, local_n, sizeof(int), cmp);
    // 4. 进行np轮排序。
    doSort(myid, local_n, np);
    // 5. 0号进程收集排序好的数据
    MPI_Gather(mykeys, local_n, MPI_INT, array, local_n, MPI_INT, 0, MPI_COMM_WORLD);
    endTime = MPI_Wtime();
    if (myid == 0)
    {
        printMatrix(array, n);
        printf("spent time = %lf second\n", endTime - beginTime);
    }
    free(array);
    free(mykeys);
    free(receive);
    MPI_Finalize();
    return 0;
}

无注释版,无语法错误,编译通过

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <time.h>
#include <stdlib.h>
//int array[] = {15, 11, 9, 16, 3, 14, 8, 7, 4, 6, 12, 10, 5, 2, 13, 1};
void merge(int mykeys[], int receive[], int n, int flag);
void odd_even_sort(int a[], int n);
void doSort(int myid, int local_n, int np);
void printMatrix(int array[], int n);
void init(int n, int myid, int np);
int getPartner(int phase, int myid, int comm_sz);
int cmp(const void *a, const void *b);
int *array, *mykeys, *receive;
int n, partner;
void Get_input(int my_rank , int comm_sz, int * n_p) {
    int dest ;
    if(my_rank ==0) {
        printf("Enter  n\n");
        scanf("%d", n_p);
        for(dest =1 ;dest < comm_sz;dest++) {
            MPI_Send(n_p,1,MPI_INT, dest,0, MPI_COMM_WORLD);
        }
    }
    else {
        MPI_Recv(n_p, 1 ,MPI_INT,0,0,MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }
}
int main(void)
{
    int i, j,n;
    int myid, np, namelen;
    char proc_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &np);
    MPI_Get_processor_name(proc_name, &namelen);
    double beginTime, endTime;
    beginTime = MPI_Wtime();
    Get_input(myid, np,  &n);
    int local_n = (n + (np - n % np)) / np; // fill with the matrix
    //初始化随机数。
    init(n, myid, np);
    // 2. 把数据广播出去。
    MPI_Scatter(array, local_n, MPI_INT, mykeys, local_n, MPI_INT, 0, MPI_COMM_WORLD);
    // 3. local sort
    qsort(mykeys, local_n, sizeof(int), cmp);
    // 4. 进行np轮排序。
    doSort(myid, local_n, np);
    // 5. 0号进程收集排序好的数据
    MPI_Gather(mykeys, local_n, MPI_INT, array, local_n, MPI_INT, 0, MPI_COMM_WORLD);
    endTime = MPI_Wtime();
    if (myid == 0)
    {
        printMatrix(array, n);
        printf("spent time = %lf second\n", endTime - beginTime);
    }
    free(array);
    free(mykeys);
    free(receive);
    MPI_Finalize();
}
void merge(int mykeys[], int receive[], int n, int flag)
{
    int mi, ti, ri;
    int *temp = (int *)malloc(sizeof(int) * n * 2);
    if (temp == NULL)
    {
        exit(-1);
    }
    mi = ri = ti = 0;
    while (mi < n && ri < n)
    {
        if (mykeys[mi] >= receive[ri])
        {
            temp[ti] = receive[ri];
            ri++;
            ti++;
        }
        else
        {
            temp[ti] = mykeys[mi];
            ti++;
            mi++;
        }
    }
    while (mi < n)
    {
        temp[ti] = mykeys[mi];
        ti++;
        mi++;
    }
    while (ri < n)
    {
        temp[ti] = receive[ri];
        ti++;
        ri++;
    }
    ti = flag > 0 ? n : 0;
    for (mi = 0; mi < n; mi++)
        mykeys[mi] = temp[ti++];
    free(temp);
}
void printMatrix(int array[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        printf("%d\n", array[i]);
}
void doSort(int myid, int local_n, int np)
{
    int i;
    for (i = 0; i < np; i++)
    {
        partner = getPartner(i, myid, np);
        if (partner != MPI_PROC_NULL)
        {
            MPI_Sendrecv(mykeys, local_n, MPI_INT, partner, 0, receive, local_n, MPI_INT, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            merge(mykeys, receive, local_n, myid - partner);
        }
    }
}
void init(int n, int myid, int np)
{
    int i;
    int total = n + np - n % np;
    if (!myid)
    {
        srand(time(NULL));
        array = (int *)malloc(sizeof(int) * total);
        for (i = 0; i < n; i++)
        {
            *(array + i) = random();
        }
        for (i = n; i < total; i++)
        {
            *(array + i) = 0x7fffffff;
        }
    }
    receive = (int *)malloc(sizeof(int) * total / np);
    mykeys = (int *)malloc(sizeof(int) * total / np);
}
int getPartner(int phase, int myid, int comm_sz)
{
    int partner;
    if (phase % 2 == 0)
    {
        if (myid % 2 != 0)
        {
            partner = myid - 1;
        }
        else
        {
            partner = myid + 1;
        }
    }
    else
    {
        if (myid % 2 != 0)
        {
            partner = myid + 1;
        }
        else
        {
            partner = myid - 1;
        }
    }
    if (partner == -1 || partner == comm_sz)
    {
        partner = MPI_PROC_NULL;
    }
    return partner;
}
int cmp(const void *a, const void *b)
{
    return *((int *)a) > *((int *)b);
}

要编写一个基于MPI(Message Passing Interface)的奇偶交换排序程序,首先我们需要了解MPI的基本概念和其在分布式内存环境下的通信机制。这是一个简单的双进程版本,用于演示如何利用MPI交换数组中的奇数和偶数元素: ```python from mpi4py import MPI # 初始化MPI环境 comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() # 定义全局数组,大小是所有进程总数的两倍 global_array = [0] * (2 * size) # 假设我们有两个进程,进程0负责偶数位置,进程1负责奇数位置 local_array = [None] * size # 随机填充本地数组 for i in range(size): local_array[i] = i + rank # 排序本地数组 local_array.sort() # 将奇偶位置的数据交换到全局数组中 if rank % 2 == 0: global_array[rank::2] = local_array else: global_array[1+rank::2] = local_array # 通知所有进程已经完成数据交换 comm.Barrier() # 打印全局数组,每个进程只打印自身范围内的部分 start = rank * 2 end = start + 2 print(f"Rank {rank}: {global_array[start:end]}") # MPI结束程序 MPI.Finalize() ``` 在这个程序中,我们首先确定当前进程的秩(rank)以及整个进程组(world communicator)的大小。然后分配一个足够大的全局数组,用于存放每个进程中数据的副本。接着,每个进程对自己的局部数据进行排序,并将奇偶位置的数据交换至全局数组。最后,各进程打印出自己处理的部分,显示排序后的结果。 注意这只是一个简化版的例子,实际上在大规模排序任务中,MPI通常会结合更复杂的算法,如快速排序、归并排序等,同时考虑效率和负载均衡。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值