MPI进程饿死问题

在编写并行计算的程序时,一定要注意“进程饿死”的问题,刚接触MPI并行计算的同学可能不太注意这个问题,也很容易写出这样的程序。那么何为饿死呢,简单讲述一下:

并行计算大佬刘文志“风辰”在《并行算法设计与性能优化》一书中给出了“饿死”几个定义(书的P140处):

所谓“饿死”是指某个控制流一直得不到计算,本质上是一种负载不均衡的问题。大多数情况下可能和优先级有关系,另外就是软件开发人员的失误。饿死的直观表现就是控制流一直在等待,就好像进入了死循环。比如系统已优先级调度控制流,软件开发人员错误滴为某个控制流分配了一个非常低的优先级,那么可能只要系统有任务并行,这个控制流就不可能得到处理器。另外一种饿死是从任务的角度来说,也即某个任务一直存在系统中,没有控制流来计算它。

我遇到的“饿死”是任务级别的,和风辰说的第二种情况类似,但是又不完全一样,是在MPI并行计算中遇到的问题。我用MPI做地震勘探中的多炮并行数值模拟,即任务级别的并行。当发4个MPI进程算7炮地震数据时,就会发生负载不均衡的问题。前三个进程都可以计算2炮,第四个进程只能计算1炮。

为了使进程同步,我们一般用MPI_Barrier(comm)语句强制所有进程在某个地方等待,这里Barrier的设置很关键,搞不好就会出现饿死的问题,我们看两段简单的代码:

有饿死问题:

        /* loop shot by shot */
        for (is=s_beg;is<s_end;is++)
        {       
            /****************** caculate forward wavefield  *******************/           
            wavefield_forward(nx,ny,nz);

            /****************** caculate residual wavefield  ******************/
            Com_Resi(nx,ny,nz);

            /****************** caculate backward wavefield  ******************/           
            wavefield_backward(nx,ny,nz);
            MPI_Barrier(comm);

            /********************** caculate gradient *********************/           
            Com_Grad(nx,ny,nz);
            MPI_Barrier(comm);

            /* collect the gradient on this processor */
            for (ixyz=0;ixyz<nxyz;ixyz++)
            {
                h_gradV[ixyz] += h_gradVT[ixyz];
            }
            MPI_Barrier(comm);    		
        }/* end shot loops */
        MPI_Barrier(comm);

当is=0时,每个进程都有任务可以计算,大家基本同步进行,此时MPI_Barrier不会出问题。

当is=1时,进程1~3还有第二炮可以算,进程4却没得任务可以算了,当遇到MPI_Barrier的时候,进程1~3就会等待进程4前来汇合,然后同步往下走,但进程4已经结束炮的计算转入下一阶段的任务处理。不幸的是,进程1~3不知道进程4已经走到下一站,在遇到MPI_Barrier还在痴痴地等待。事实上即便等上一万年,进程1~3都等不到进程4在这一环节上来汇合了,这就是发生了饿死的问题。

无饿死问题:

        /* loop shot by shot */
        for (is=s_beg;is<s_end;is++)
        {       
            /****************** caculate forward wavefield  *******************/           
            wavefield_forward(nx,ny,nz);

            /****************** caculate residual wavefield  ******************/
            Com_Resi(nx,ny,nz);

            /****************** caculate backward wavefield  ******************/           
            wavefield_backward(nx,ny,nz);
            // MPI_Barrier(comm);

            /********************** caculate gradient *********************/           
            Com_Grad(nx,ny,nz);
            // MPI_Barrier(comm);

            /* collect the gradient on this processor */
            for (ixyz=0;ixyz<nxyz;ixyz++)
            {
                h_gradV[ixyz] += h_gradVT[ixyz];
            }
            // MPI_Barrier(comm);    		
        }/* end shot loops */
        MPI_Barrier(comm);

这里,我们把循环中的MPI_Barrier都注销掉。即让这四个进程独立地计算任务,相互之间不用等待。这样进程1~3在算第二炮时就不会再痴痴地等待进程4。在循环结束后设置MPI_Barrier,意在告诉这四个进程在循环计算的过程中可以独立地行计算,但在循环计算结束后,必须停下来等待,等到4个进程都跑到这里时再转入下一阶段的计算。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder802

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值