[并行计算]Matlab并行计算工具箱(Parallel Computing Toolbox)官方文档教程中文版(4)

嵌套的parfor循环和for循环

如下面的代码所示:

Code #4-1
1.parfor i = 1:10  
2.MyFun(i)  
3.end  
4.
5.function MyFun(i)  
6.parfor j = 1:5  
7.  	...  
8.end  
9.end  

代码#4-1为在循环里面调用一个函数,同时该函数也使用parfor做并行计算,然而,在语句parfor i = 1:10执行后,处理器的并行计算就只会落在这条语句,其余后面开启的并行parfor并不会生效。

 

将嵌套循环转换为parfor时的注意点

下列代码片实现一个典型的双循环二维数组赋值功能,在我的电脑上跑出来的时间约为42.3秒。

Code #4-2
1.A = 100;  
2.tic  
3.for i = 1:100  
4.for j = 1:100  
5.a(i,j) = max(abs(eig(rand(A))));  
6.end  
7.end  
8.toc  

现在,由我们前文的叙述可知,双圈循环只能改装一个for为parfor实现并行计算,那么,在这一个代码片#4-2中应该改装哪个for才能实现最高效的计算呢,下面给出一种度量方法,在代码片#4-3中加入了输入输出数据量观察ticBytes字眼,并改装第一个for循环为parfor循环。

Code #4-3
1.A = 100;  
2.tic  
3.ticBytes(gcp);
4.parfor i = 1:100  
5.for j = 1:100  
6.a(i,j) = max(abs(eig(rand(A))));  
7.end  
8.end 
9.tocBytes(gcp)
toc 

在笔者的双核笔记本上跑出来差不多是快了2倍,证明这个parfor的改装是具备较高的效益的,下面我们来看改装另一个parfor的结果代码#4-4。

Code #4-4
1.A = 100;  
2.tic  
3.ticBytes(gcp);
4.for i = 1:100  
5.parfor j = 1:100  
6.a(i,j) = max(abs(eig(rand(A))));  
7.end  
8.end 
9.tocBytes(gcp)
toc 

跑出来的时间稍微慢了一点,虽然不算很差,认真看我们发现内嵌的parfor循环的数据量比外循环版本大了一个量级,那么为什么会出现这样的差别呢,万能的Matlab官方文档中并没有给出答案,本文作者给出的一个合理的解释如下:

  1. 使用外层的并行计算,内层做多而数据量不大的循环计算,cpu的物理内核从一开始就分配到了内层的一个整个循环任务,因此计算的效率较高,传入传出的数据量较少;
  2. 相比较下,使用内层作为parfor并行的话,在任务上的计算是和外层一致的,但一圈j = 1:100计算完后,parfor结束,由外层循环i重新进入parfor循环时,cpu会需要消耗进入parfor模式分配并行,此时是存在开销的;

这个实验证明了频繁启动parfor是有负面影响的,因此改装外层并行比内层快是合理的。

嵌套循环中变量的使用注意事项

观察下面左边的代码片在内层循环中j的上限需要实时计算矩阵A的列数,然而,在数据的处理段同样有读写数组A的行为,因此这样的效率是不高的,如右侧代码片所示,先把矩阵A的列上限求出再进行计算是一个高效的方法。

无效

有效

A = zeros(100, 200);

parfor i = 1:size(A, 1)

   for j = 1:size(A, 2)

      A(i, j) = i + j;

   end

end

A = zeros(100, 200);

n = size(A, 2);

parfor i = 1:size(A,1)

   for j = 1:n

      A(i, j) = i + j;

   end

end

如下面左面代码片的问题是使用隐含的矩阵索引j+1,在并行计算中索引数组时应尽量使用循环i和j的直接索引写矩阵,右代码片所示。

无效

有效

A = zeros(4, 11);

parfor i = 1:4

   for j = 1:10

      A(i, j + 1) = i + j;

   end

end

A = zeros(4, 11);

parfor i = 1:4

   for j = 2:11

      A(i, j) = i + j - 1;

   end

end

 

如下面的代码片所示,若嵌套循环中使用了矩阵A,则不可以在第一层循环中直接读取矩阵A是,因为第一层循环正在并行计算的模式下,右边的代码是合法的,因为其声明了一个临时变量

 

无效

有效

A = zeros(4, 10);

parfor i = 1:4

    for j = 1:10

        A(i, j) = i + j;

    end

    disp(A(i, 1))

end

A = zeros(4, 10);

parfor i = 1:4

    v = zeros(1, 10);

    for j = 1:10

        v(j) = i + j;

    end

    disp(v(1))

    A(i, :) = v;

end

 

下面左边代码的问题是,在parfor循环的内嵌循环中,索引不允许割裂,右则代码是一个正确的示范,可以允许通过条件分支判断,但循环索引是需要连贯的。

 

无效

有效

A = zeros(4, 10);

parfor i = 1:4

   for j = 1:5

      A(i, j) = i + j;

   end

   for k = 6:10

      A(i, k) = pi;

   end

end

A = zeros(4, 10);

parfor i = 1:4

   for j = 1:10

      if j < 6

         A(i, j) = i + j;

      else

         A(i, j) = pi;

      end

   end

end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值