Matlab并行计算

在利用matlab进行计算时,会遇到循环次数过大,或者是单次计算量过大的问题,比如需要计算的数值阵列数据量过大,利用传统的编程方式,跑一次程序几个小时。如果遇到这种情况,则可以尝试一下MATLAB并行计算,传统的计算方式都是串行计算。并行计算之所以可行,取决于两方面因素:a)现在大家的计算机是多核的,至少也是双核了吧,有的可能8核都有,这是很重要的硬件基础。b)MATLAB本身提供了很好的并行计算函数,加上你的聪明智慧,设计合理的软件,这样就有了软件基础了。

加速matlab运行的三重境界提高MATLAB运行效率

I. 如何并行计算

并行运算其实就是主线程和子线程的一个任务分配和汇总的实现。这种实现过程需要三个基本步骤:1、需要创建几个workers。2、把任务划分,然后分配给workers。3、整合结果,释放workers。

首先打开MATLAB命令窗口,输入matlabpool open就OK了。当然也可以配置使用核心数:matlabpool open local 4。最好就是有几个核心就开几个,这样效率比较高。

当程序运行完成后,释放workers:matlabpool close

II. 并行编程方法

具体实现parallel program主要是通过parfor(parallel for)和SPMD(single program, multiple data)完成的。parfor,spmd不可以相互或者自身嵌套。其他关于spmd vs. parfor的可以参考这个帖子

II.I. parfor(parallel for)

parfor只用于matlab并行循环。当你需要简单计算的多次循环迭代时,例如蒙特卡洛(Monte Carlo)模拟,parfor循环就很有用。parfor将循环迭代分组,那么每个worker执行迭代的一部分。当迭代耗时很长的时候parfor循环也是有用的,因为workers可以同时执行迭代。这种循环代替有几点说明:

  1. 使用parfor前提必须开启matlabpool,否则等于for。

  2. 要求各个循环的内容是独立的(independent)。parfor不能像for一样多层内嵌。parfor不能调用与上一个循环结果相关的变量,否则就等与for了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    % 都可以把for循环改成parfor
    total = 0.0;
    big = - Inf;
    for i = 1 : n
    total = total + x(i);
    big = max ( big, x(i) );
    end
    for i = 1 : n
    angle = ( i - 1 ) * pi / ( n - 1 );
    t(i) = cos ( angle );
    end

    % 这种依赖前一个循环的结果则不能转换成parfor
    % 还有有用到break continue return 这些类型都不能使用parfor
    dx = 0.25;
    x = zeros (1,n);
    for i = 2 : n
    x(i) = x(i-1) + dx;
    end
  3. 所谓透明(transparency),即指parfor循环体中不能出现类似eval一类的函数。一个程序并行时要共享内存,而eval语句可能使程序进入错误的workspace,因此不要用eval,改用不同index赋值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    % 不能出现类似eval一类的函数
    parfor i=1:10
    eval(['disp(num2str(i))'])
    end

    %改用不同index赋值
    matlabpool local 2;
    c = 1:5;
    parfor i = 1:length(c)
    a(i) = c(i);
    end
  4. 当parfor的循环体中存在对同一个矩阵的不同部分的操作时,会报错。原因在于matlab的parfor功能不允许循环体中出现对矩阵的某些部分独立地计算。 笼统说来,解决方法是将循环体中计算或者修改的内容记录在一个temp矩阵中,parfor循环全部完成后,再简单地用for将temp中的内容赋值给实际需要的矩阵即可1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    %% 直接将for改称parfor是会出错的。
    clear
    A1=magic(6);
    x=unique(ceil(rand(1,10)*36));
    parfor i=1:length(x)
    A1(x(i))=1000+round(rand(1)*36);
    end

    %% 对这个特定问题,甚至不需要循环
    clear
    A1=magic(6);
    x=unique(ceil(rand(1,10)*36));
    A1(x)=A1(x)+1000+round(rand(1,length(x))*36);

    %% 解决方法是将循环体中计算或者修改的内容记录在一个temp矩阵中
    matlabpool local 2
    clear
    A2=magic(6);
    x=unique(ceil(rand(1,10)*36));
    temp=[];
    parfor i=1:length(x)
    temp=[temp [x(i);round(rand(1)*36)+1000]];
    end
    for i=1:length(x)
    A2(temp(1,i))=temp(2,i);
    end
    matlabpool close

II.I.I. 案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
tic
%传统方式计算
c1=1;
for i = 1:500
c1 = c1+max(eig(rand(i,i)));
end
t1 = toc;

matlabpool open local 12;
%parfor并行方式计算
tic
c2=1;
parfor ii = 1:500
c2 = c2+max(eig(rand(ii,ii)));
end
t2 = toc;
matlabpool close;

display(strcat('parfor并行计算时间:',num2str(t2),'秒'));
display(strcat('客户端串行计算时间:',num2str(t1),'秒'));

II.II. SPMD(single program, multiple data)

Spmd中的“Single program”方面指的是同一段代码运行在不同的多个lab上,就是说同一段程序应用于不同的样本(数据),所以一般针对随机抽样的并行 。你在一个Matlab客户端上运行一个程序,被标志为spmd模块的其他部分运行在其他lab上。当这些块运行完毕后,你的程序继续在客户端运行。 “Multiple data”方面指的是虽然spmd语句在所有的lab上运行相同的代码,但每一个lab可以有不同的,独有的数据。所以多数据集可以在多个lab上同时被容纳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
%% SPMD  
%example 1
spmd
A = rand(3,2); %generate a matrix A for each lab(worker)
end
for i = 1:length(A)
figure; imagesc(A{i});
end

%example 2
a = 3;
b = 4;
spmd
c = labindex();
d = c+a;
end
c{2} = 5;
spmd
f = c*b;
end
for i = 1:length(f)
fprintf('%d\t',f{i});%access the value of each lab
end

另外,SPMD也可以用于可替代parfor的块并行,在不同lab(worker)上对相同或不同的数据执行不同的并行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%example3 - deal with same Data by different parameters  
%add different values to same array Data
Data = 1:100;
spmd
switch labindex
case 1
Data = Data+1;
case 2
Data = Data+2;
end
end
% print Data{1} & Data{2} for checking

%example4
%add different values for different parts of array Data
% [1:50]+1
% [51:100]+2
spmd
if labindex == 1
Data(1:50) = Data(1:50)+1;
else
Data(51:100) = Data(51:100)+2;
end
end

III. BUG调试

  1. matlabpool Java exception occurred: java.net.UnknownHostException: Your_Host_Name at java.net.InetAddress.getLocalHost(Unknown Source): 在/etc/hosts这个文件里增加一行我们本地ip和主机名即可:127.0.0.1 Your_Host_Name,Your_Host_Name这个每个人电脑都不同。