经常用matlab处理大型数据,有时某些数据处理起来可能要几天甚至更久。如果算法已经到最优,那么提高速度的最后方法就是从硬件下手了。在这个什么都开始并行的年代,matlab也提供了并行计算的功能,甚至能用GPU加速。matlab貌似在2010a开始支持并行计算,引入了一个工具箱,叫做parallel computing toolbox.它的使用方法,可以从matlab的帮助获得。
我现在对matlab并行的研究还只是冰山一角,只研究了它parfor的用法。可以再google中输入matlab parfor,你将得到足够多的资料来了解这是个什么东西,如果你耐心,建议去研究研究matlab 帮助中对parfor的说明。这里我只大概讲一下parfor。parfor就是paralle+for,也就是并行的for循环,怎么个并行法?我理解就是,matlab会弄出几个虚拟的小pc,一个算i=1:30部分循环,一个算i=50:80部分循环,再来一个算i=90:120部分循环,当然数字是我瞎编的,我是想说matlab将一个大循环分成小块,然后这些小块并行计算,最后再合在一起。这样,有一个问题,因为普通的循环是从i=1算到i=100,一个接一个算,如果下一次循环要依赖上一次循环怎么办?如果出现这种情况,那就不能用matlab的parfor了。用parfor的前提条件就是,循环的每次迭代独立,不相互依赖。举个简单的例子,计算1+2+3...+100就可以用parfor,但是如果计算斐波那契数列的前100个数字,那就不能用parfor了。
parfor就先解释到这里,其实它涉及到的东西远不止这些,而且感觉很令人纠结,如果你的C++很好,那就直接用C++吧!如果你还是想用matlab做并行,那就可以继续向下看看我的一些经验。
首先我是做图像处理的,1000多个图像,如果直接算可能要算上1天,所以我想用matlab的并行。我们都知道数字图像可以看成矩阵,我们经常用for循环里面再加一个for循环来处理,但是parfor循环不能嵌套。那么原来的
for i=1:N
for j=1:M
end
end
就必须改成
parfor i=1:N
for j=1:M
end
end
或者
for i=1:N
parfor j=1:M
end
end
但是,这都不是最好的方法,因为如果循环的次数太少,并行就显现不出威力来,所以最好的方法是这样:
for k=1:M*N
i=mod(k-1,M)+1 %行号
j=floor((k-1)/M)+1 %列号
end
要注意一点的是k是按照列来数的,也就是这样
1 4 7
2 5 8
3 6 9
所以,行号和列号别算错了。这样其他代码就可以不变了。
还需要注意的一点就是就是,如果对矩阵f的每个像素计算的点值要赋值给矩阵g。这个g要在循环外面声明好,而且要固定大小,在parfor循环里面最好也是向量,而非矩阵。计算完成后再用vec2mat函数转换为矩阵,这个函数之后,可能还需要个转置才能得到你需要的结果。
至于提高的速度来讲,我处理一个680*340的矩阵,用2核提高了2倍,用4核提高了6倍。
然后就是如何声明你要开启的核(通常来讲就是你的Pc有几个核就声明几个)?
首先在matlab命令行里输入:matlabpool open local 4
然后它会提示你一些消息,开启成功后就像以前一样操作就行。不想用了就再输入matlabpool close,关闭并行。
这些内容也可以写到函数里面去,比如
function yourFun()
....
matlabpool('open','local',4); %最后一个参数是你要开启的线程数
parfor i=1:N
...
end
matlabpool close
....
end
如果你的parfor怎么都通不了,或者速度变得更慢了,建议看matlab 帮助中的这一部分,看明白了,自然就有答案了:
今天把一个以前的代码改成了可以支持parfor的版本。 parfor好像只有matlab 2008a以上的版本才支持吧。按照官方的文档,好像是一个核可以开启一个job worker。俺的电脑是4核8线程的。使用默认local设置的时候,只看到cpu的使用率是50%。总是不爽。老想着要是它可以支持8个多好啊。这样怎么算都是单核的8倍了。。。鼓捣了一阵,还是不行。好像就是只能只能开启最多跟cpu核心数一样的worker了。 那就不管它了,4倍就4倍吧。聊胜于无。 第二个问题就是for循环里面调用了别的函数的变量。以前为了省事,就用了一把一把的global。但是在parfor里面,这个global是会出问题的。运行了一下,真的出问题了。侥幸都侥幸不过去了。 网上找了几个替代的方案: 在编制MATLAB程序的过程中,常常会遇到多个函数里要调用同一个变量的情况,这时候,一般采用全局变量(global)实现这样的“变量共享”,但是global变量在每次使用前,必须进行声明,使用不方便。作者根据自己使用MATLAB的经验,采用MATLAB自带的evalin函数和assignin函数,可以较好的解决全局变量使用时所带来的不便,实现多个函数共享一个变量的功能。具体如下: A1=evalin('base','A2') %将workspace中变量A2赋值给函数中里的变量A assignin('base','R',D/2) %将D/2的值输出到workspace,生成新的变量R 有兴趣的朋友,赶紧试试吧~~~~~~ 也挺麻烦的,毕竟那么多变量,一个一个的写,对代码的改动太大,以后容易出问题。 那么最简单的办法呢,还是觉得直接把那些变量save到一个mat文件里面。在别的函数load一下就行了。 这样就避免了global的使用。 尝试了一下,可以,还是50%的cpu。 出来的结果也是正常的。 好歹也算是比4个小时少了3个小时了。 以后再看看matlab多线程的并行是咋搞的
Mathwoks在Matlab R2007a版本的Parallel Computing Toolbox(并行计算工具箱)中加入了并行循环parfor-loops,对于每一步可以独立于其他步的循环,计算效率可以有较大幅度的提高。以前简单的for循环for-loop是顺序的(sequentially)执行每一步循环体(statement),parfor-loop是通过将各个循环体分配到不同的节点上进行并行计算。所以parfor的要求是循环体之间相互独立,结果各不影响,Matlab的编辑器会自动帮你检查循环体的结果是否影响。当你初始化一个matlab进程时,这个进程被称为Matlab Client,它起着和用户交互和调度的作用。在并行计算工具箱中,通过matlabpool可以打开多个matlab进程,这些进程被称为Matlab Worker。并行循环parfor-loop的各个循环就是随机的分配到这些Matlab Worker上进行同时的计算。最后再返回给Matlab Client. 在一个多核桌面上可以本地同时运行四个 worker (至R2009a,4.1版可达8个),如果与 MATLAB Distributed Computing Server 集成,就可以使用集群中任意数量的机器作为worker了。
一个使用parfor-loop的例子:
1 2 3 4 5 6 7 8 9 |
%example of parfor-loop %本地worker数通常等于cpu的核数 matlabpool open local 2; parfor i=1:1024 A(i) = sin(i*2*pi/1024); end plot(A); matlabpool close; |