【问题标题】:Using Loops in MPI在 MPI 中使用循环
【发布时间】:2016-01-17 22:50:50
【问题描述】:

我正在尝试通过反转和在 C 上使用 MPI 编码来对大型数组进行排序。

基本上,我的程序将数组拆分为工作人员的部分,每个工作人员找到自己的增加和减少条带并将条带发送回根。 Root 通过查找和使用这些条带的最大和最小元素来进行一些反转。程序在没有剩余断点时结束,表示数组已排序。

这是一个很长的代码,所以我简化了我的问题:

int *ARRAY;

int main(int argc, char *argv[]) 
{ 
    int p_id, n_procs, flag = 1;
    MPI_Init(&argc, &argv);
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD, &p_id);
    MPI_Comm_size(MPI_COMM_WORLD, &n_procs);

    if(p_id == 0) { 

        ARRAY = createRandomArray(N_DATA);
        // PRINT UNSORTED ARRAY

        while(hasBreakPoints(ARRAY, N_DATA)) {

            for(i=1;i<n_procs; i++) 
                // SEND PORTIONS TO WORKERS

            for(i=1;i<n_procs; i++)
                // RECEIVE EACH STRIP FROM WORKERS

            // FIND MAX AND MIN OF STRIPS
            // MAKE REVERSALS ON "ARRAY"    
        }
        flag = 0;
        // PRINT SORTED ARRAY
    }
    else {

        while(flag == 1) {
            // RECEIVE PORTION FROM ROOT
            // FIND MY OWN STRIPS
            // SEND MY OWN STRIPS TO ROOT
        }

    }
    MPI_Finalize();
    return 0;
}

如您所见,我需要使用while 循环来运行程序,直到没有剩余断点。我知道MPI_Send 命令的数量必须等于MPI_Receive 命令的数量。所以,我只是创建了一个标志来运行 ROOTWORKERS 相等的时间。

通过使用这种惰性方法,程序可以正常运行但永无止境,也不会进入MPI_Finalize。这种或更有效的使用方式是否有任何修复?感谢您的帮助。

【问题讨论】:

  • 我发现worker比root多运行一次。因此,它在MPI_Recv 声明处无限等待。我该如何解决?
  • 您的 flag 变量未在 MPI 进程之间共享...您如何期望进程 #0 更改其 flag 变量的值这一事实被传输到其他进程?跨度>
  • @Gilles 哦,你是对的。我错过了这一点。对不起,我是并行编程的新手。我怎么解决这个问题?谢谢。

标签: c++ c parallel-processing mpi


【解决方案1】:

您的flag 变量是每个进程的本地变量,您必须找到一种方法,在它发生变化时将其值从进程#0 转移到其他进程。

实际上,您可以通过使用消息标签来解决这个问题。您的工作进程可以使用MPI_ANY_TAG 从root 接收并决定下一步做什么,即发回数据或只是完成,这取决于收到的实际标签值。这可能看起来像这样(未经测试):

int *ARRAY;

int main(int argc, char *argv[]) 
{ 
    int p_id, n_procs, flag = 1;
    MPI_Init(&argc, &argv);
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD, &p_id);
    MPI_Comm_size(MPI_COMM_WORLD, &n_procs);

    const int COMPUTE=1, STOP=2;

    if(p_id == 0) { 

        ARRAY = createRandomArray(N_DATA);
        // PRINT UNSORTED ARRAY

        while(hasBreakPoints(ARRAY, N_DATA)) {

            for(i=1;i<n_procs; i++) 
                // SEND PORTIONS TO WORKERS using tag COMPUTE
                MPI_Send(......, COMPUTE, ...);

            for(i=1;i<n_procs; i++)
                // RECEIVE EACH STRIP FROM WORKERS

            // FIND MAX AND MIN OF STRIPS
            // MAKE REVERSALS ON "ARRAY"    
        }
        // send the STOP message using tag STOP
        for(i=1;i<n_procs; i++)
             MPI_Send(....,  STOP, ...);
        // PRINT SORTED ARRAY
    }
    else {

        while(flag == 1) {
            // RECEIVE PORTION FROM ROOT using MPI_ANY_TAG
            MPI_Recv(..., MPI_ANY_TAG, ..., &status);
            if ( status.MPI_TAG == COMPUTE ) {
                // FIND MY OWN STRIPS
                // SEND MY OWN STRIPS TO ROOT
            }
            else
                flag = 0;
        }

    }
    MPI_Finalize();
    return 0;
}

【讨论】:

  • 吉尔斯,谢谢!这是一个非常聪明的解决方案 :) 我想知道我应该发送什么样的 STOP 消息?通常我会将整个数组发送给带有 COMPUTE 标签的工作人员。最后,我应该用 STOP 标签再次发送整个数组吗?我试过了,这种方法有效,但我认为这对性能不好?谢谢。
  • 您无需发送任何内容。你可以只做MPI_Send(NULL, 0, ..., STOP, ...);,其余的都无所谓。
【解决方案2】:

正如 Gilles 指出的那样,flag 不能用于我的程序。我通过检查数组是否在 ROOTWORKER 的部分中都已排序来解决了这个问题。为此,我必须将ARRAY 传递给来自ROOT 的工人。并且,我可以选择将 ARRAY 保留在工作人员部分,作为 LOCAL

int *ARRAY;

int main(int argc, char *argv[]) 
{ 
    int p_id, n_procs;
    MPI_Init(&argc, &argv);
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD, &p_id);
    MPI_Comm_size(MPI_COMM_WORLD, &n_procs);

    if(p_id == 0) { 

        ARRAY = createRandomArray(N_DATA);
        // PRINT UNSORTED ARRAY

        while(hasBreakPoints(ARRAY, N_DATA)) {

                for(i=1;i<n_procs; i++) 
                // SEND WHOLE ARRAY TO ALL WORKERS

                for(i=1;i<n_procs; i++) 
                // SEND PORTIONS TO WORKERS

            for(i=1;i<n_procs; i++)
                // RECEIVE EACH STRIP FROM WORKERS

            // FIND MAX AND MIN OF STRIPS
            // MAKE REVERSALS ON "ARRAY"    
        }          
        // PRINT SORTED ARRAY
    }
    else {

        int *LOCAL;
        // RECEIVE ARRAY TO LOCAL

        while(hasBreakPoints(LOCAL, N_DATA) {
            // RECEIVE PORTION FROM ROOT
            // FIND MY OWN STRIPS
            // SEND MY OWN STRIPS TO ROOT
        }

    }
    MPI_Finalize();
    return 0;
}

虽然我不明白如何,但这解决了我的问题。我仍然愿意听取你的意见。谢谢。

【讨论】:

  • 我意识到在某些情况下,在 WORKER 站点中仅接收一次 ARRAY 是行不通的。所以,这不是一个精确的解决方案。我按照 Gilles 的方法解决了这个问题 :)
猜你喜欢
  • 1970-01-01
  • 2016-03-28
  • 2015-11-01
  • 1970-01-01
  • 2016-09-01
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多