当matlab计算量很大,重复独立的循环计算很多的时候,我们可以使用matlab的并行计算,这里我先试验了parfor并行计算。以下代码仅适合新版的matlab,改编自《实战matlab之并行程序设计》。
启动代码:
function [pool] = startmatlabpool(size)
pool=[];
isstart = 0;
if isempty(gcp('nocreate'))==1
isstart = 1;
end
if isstart==1
if nargin==0
pool=parpool('local');
else
try
pool=parpool('local',size);%matlabpool('open','local',size);
catch ce
pool=parpool('local');%matlabpool('open','local');
size = pool.NumWorkers;
display(ce.message);
display(strcat('restart. wrong size=',num2str(size)));
end
end
else
display('matlabpool has started');
if nargin==1
closematlabpool;
startmatlabpool(size);
else
startmatlabpool();
end
end
关闭代码:
function [] = closematlabpool
if isempty(gcp('nocreate'))==0
delete(gcp('nocreate'));
end
测试代码:
pool = startmatlabpool(4);
N=1000;
M=100;
data = cell(1,N);
for kk = 1:N
data{kk} = rand(M);
end
display(strcat('datasize:',num2str(N*M*M/1024/1024),'M doubles'));
tic;
parfor ii = 1:N
c1(:,ii) = eig(data{ii});
end
t1 = toc;
display(strcat('parafor:',num2str(t1),'seconds'));
tic;
for ii = 1:N
c2(:,ii) = eig(data{ii});
end
t2 = toc;
display(strcat('for:',num2str(t2),'seconds'));
closematlabpool;
结果:
datasize:9.5367M doubles可以看出parfor计算速度快了一半。
问答1:能否汇总各个线程的数据?
在openMP中也有这个问答:
for i = 1 : 1000
sum = sum + i;
end
如果是并行的话,每个A在线程中都有自己的一份拷贝,那么最后得到的A是不可预计的。
openMP的解决方法是增加了reduction子句:
#pragma omp parallel for reduction(+: sum)
for ( i = 1; i < 1001; i++ )
{
sum += i;
}
这样sum就是1-1000的和。
在matlab中,matlab自己会默认把sum的加法设置为reduction加法,称为简约/规约操作,反正不进行这个操作的话也没有其他意义。ORZ
代码:startmatlabpool(4)
sum = 0;
parfor i = 1:1000
sum = sum + i;
end
sum
closematlabpool;
结果:sum=500500
事实上可以进行连续操作的操作符都支持简约操作,比如*,.*,+,-,&,|,[,expr]等等。
不过简约操作有很多陷阱,所以简化并行操作和增加一致性是非常必要的。
问答2:parfor的变量有什么讲究?
其实没什么讲究,比起openMP来parfor要简单的多,好用说不上,但是方便简单的并行操作。所有的变量直接用就行了,书上的各种变量种类都是唬人的,不过请注意非简约操作情况下答案是否正确,以及不要随便修改输入变量(修改后的结果无法预计)。
问答3:parfor语句作用域能用break吗?
答案是不能。这个不能在特定情况下直接退出,就是说一旦运行就要执行下去。另外parfor是最低端的并行语句,在作用域内部也不能使用spmd,parfor嵌套,不过可以使用含有parfor的函数。
问答4:什么时候使用parfor
其实用了一下感觉他的作用并不大,各种并行控制手段都没有……如果数据量特别大,各个循环域之间相对独立,就可以用parfor。另外matlab启动并行环境也比较慢。