在Maple中使用Grid包实现并行计算

最近导师给了个Maple实现并行计算的任务,具体就是求一个马尔可夫链中的状态转移概率矩阵,由于每个转移概率的公式比较复杂(不只是因为矩阵本身的尺寸比较大,矩阵大小范围从100x100到2000x2000)。在使用串行计算的情况下,计算一个200x200的矩阵,所需时间约为330s,2000x2000时耗时5天不止。
Maple Programming Guide中给出了两种并行模型,一种称为Task Programming Model(任务编程模型),它的并行是线程级的(在一个进程下运行多个线程实现并行),线程间的通信通过共享内存实现。另一种称为Grid Programming Model(不知怎么翻译),实现进程级的并行(也可以实现在一个网络上的分布计算,参看Grid:-Setup帮助),进程间的通信通过Send/Receive函数实现。
就我们的问题而言,使用Task Programming Model是最自然的想法,各个线程只需共享一个用于存储矩阵的全局变量,然后分别计算矩阵的不同区域并写入,线程之间不需要交流什么信息,也不需要考虑各个线程的不同运行顺序(因为他们计算不同的区域)。我认为这个想法没有错,但在实际操作上遇到了一些问题。调试之后我认为是计算概率时使用了numbcomb函数来求组合数,而这个函数并非是Thread-safe的,也就是说多个线程同时调用这个函数会产生预料之外的问题。
这里可能可以通过重写一个numbcomb实现,但是我还是决定改用Grid来做。用Grid时一定要明白每个节点有一个单独的运行环境,这里的运行环境包括执行任务的函数,环境变量(包括像Digits这样的变量)。Launch任务时需要将这些环境发送给每一个节点。节点运行结束后,只会接受第一个节点(Node 0)返回的结果。所以一般来说Node 0都是负责任务的调度的调度,以及接受处理其他节点的运算结果。

具体代码:

CalculateTransitionMatrix := proc()
    uses Grid;
    global m,r,CV,ROU,P;
    local this_node,nodes_num,current_job,j,k,result,count;
    
    this_node := MyNode();
    nodes_num := NumNodes();
    
    if this_node <> 0 then 
        while true do
            current_job := Receive(0);
            if current_job < 0 then break; end if;
            result := NULL;
            for j from 1 to m+r+2 do
                result := result, CalculateTransitionProbability(current_job-1,j-1,m,r,CV,ROU);
            end do;
            result := this_node, current_job, result;
            Send(0, result); 
        end do;
    else
        P := Matrix(m+r+2,m+r+2);
        for current_job from 1 to nodes_num-1 do
            Send(current_job,current_job);
        end do;
        count := 0;
        while count < nodes_num - 1 do
            result := Receive();
            
            j := result[1];
            Send(j,current_job);
            
            if current_job = -1 then 
                count := count + 1;
            end if;
            
            if current_job <> -1 then 
                current_job := current_job + 1;
            end if;
            
            if current_job > m+r+2 then
                current_job := -1;
            end if;

            j := result[2];
            for k from 1 to m+r+2 do
                P[j,k] := result[k+2];
            end do;
        end do;
    end if;
    Barrier();
end proc;

Grid:-Launch(CalculateTransitionMatrix,imports=['CalculateTransitionProbability','m','r','CV','ROU','Px','Py','Digits'],exports=['P']);

其中CalculateTransitionProbability计算矩阵中的一个元素。整个模型很简单除了Node 0之外的其他节点每次计算矩阵中的一行。Node 0负责接受其他节点计算出的结果,然后要计算的下一行的行号发给该节点,没有多余的计算任务时发送-1。接收到-1的节点终止任务,当0号节点给其他每个节点都发送了-1之后结束。

Node 0中的几个if逻辑稍微有些混乱,应该按照Code Complete中的几个原则改写一下的。之前有个改好的版本,但没在这台机子上。

另外值得注意的一点事,Grid:-Launch()在不指定numnodes的情况下,默认启动的节点数为当前CPU的逻辑核心数,比如在E3-1240 V2的机器上会启动8个节点进行运算。

转载于:https://www.cnblogs.com/jerry-wangbin/archive/2013/06/11/3132061.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值