|
发表于 2012-5-9 21:13:52
|
显示全部楼层
MATLAB并行计算
0 B2 ^6 s+ n# ?# m- Q4 l% d先转下网上找到的资料。9 ?& `9 T3 B& r3 v+ A6 i u
一、Matlab并行计算原理梗概, Z& _4 y* e @1 R2 j
Matlab的并行计算实质还是主从结构的分布式计算。当你初始化Matlab并行计算环境时,你最初的Matlab进程自动成为主节点,同时初始化多个(具体个数手动设定,详见下文)Matlab计算子节点。Parfor的作用就是让这些子节点同时运行Parfor语句段中的代码。Parfor运行之初,主节点会将Parfor循环程序之外变量传递给计算子节点。子节点运算过程时互不干扰,运算完毕,则应该有相应代码将各子节点得到的结果组合到同一个数组变量中,并返回到Matlab主节点。当然,最终计算完毕应该手动关闭计算子节点。
6 X4 S/ r$ H4 ?二、初始化Matlab并行计算环境
7 |) t w6 R4 P, f6 ^这里讲述的方法仅针对多核机器做并行计算的情况。设机器的CPU核心数量是CoreNum双核机器的CoreNum2,依次类推。CoreNum以不等于核心数量,但是如果CoreNum小于核心数量则核心利用率没有最大化,如果CoreNum大于核心数量则效率反而可能下降。因此单核机器就不要折腾并行计算了,否则速度还更慢。下面一段代码初始化Matlab并行计算环境:2 u8 h# F/ G" a
%Initialize Matlab Parallel Computing Enviornment by Xaero | Macro2.cn/ f+ Z3 ~; r4 ]0 a) M
CoreNum=2; %设定机器CPU核心数量,我的机器是双核,所以CoreNum=2
: {; {8 Y( y5 ?% Dif matlabpool('size')<=0 %判断并行计算环境是否已然启动; B/ X: z! N6 |! Z
matlabpool('open','local',CoreNum); %若尚未启动,则启动并行环境
* |. L5 B- S8 Q2 g. L% jelse
7 D+ G, l: O$ u$ ]* p1 A* i# Ndisp('Already initialized'); %说明并行环境已经启动。3 r9 S0 q1 r# M6 Q
end9 P# @' a4 f2 c' g5 Y( T
* w" Q9 K( W! ~# h$ L
运行成功后会出现如下语句:* E! C: s* f8 x% {" W
Starting matlabpool using the 'local' configuration ... connected to 2 labs.
6 k/ [+ C. u6 p9 }- w8 N7 R* B( {如果运行出错,按照下面的办法检测:
2 ~- [% S5 u2 \( F首先运行:
. }& ]* h% t1 x1 n' Q" p8 f6 Ymatlabpool size
2 M/ c7 C: p' `+ W & W+ h: D' T2 A, W
如果出错,说明你没有安装Matlab并行工具箱。确认安装了此工具箱后,运行:
) ~) `6 Z% N# Y q5 Q7 b5 i2 N- ematlabpool open local 2; X/ }8 N5 z5 d4 U9 U* k
如果出错,证明你的机器在开启并行计算时设置有问题。请联系MathWorks的售后服务。* C; g: p1 y" I2 R, [! ?
- n& e/ z9 r9 A, v8 ~6 c/ t7 W三、终止Matlab并行计算环境
6 a& f" M8 l& w- A$ @5 N用上述语句启动Matlab并行计算环境的话,在你的内存里面有CoreNum个Matlab进程存在,每个占用内存都在百兆以上。(可以用Windows任务管理器查看),故完成运行计算后可以将其关闭。关闭的命令很简单:
) |) E& k0 Z t7 x Omatlabpool close
/ j$ m$ z5 Q* m" Z
, Y" B$ }, N* t* ^四、Matlab做Monte Carlo并行的算法% Q9 j8 K% j# p0 `9 x$ D- X6 h) L
Matlab并行计算比较特别。下图节选自Matlab并行计算工具箱用户手册。这个列表告诉你Matlab如何处理Parfor并行计算程序段中的各种变量。所以写代码时要注意不少问题,否则写出的并行代码可能还不如非并行的代码快。
' v V, N& J4 Q4 p0 }# z
1 b1 O4 i9 G8 m; J这里我推荐大家用Matlab写Monte Carlo并行代码时按照以下注意事项来写:
0 ~; L; j" D% ] k9 y1.将Monte Carlo模拟过程中不会改变的参数都写在Parfor循环块外面
1 _. `, b! o& T& {# ?# r$ U, C2.生成随机数、计算f(x)等过程都写在Parfor里面
9 R0 O P6 c, |! p3.不要将V0结果传递出Parfor,而是直接计算出V0的均值、方差传递出parfor。; ~- y, `5 `7 O6 C
4.最后用数学公式将传递出Parfor的V0的均值方差组合计算成最终结果
7 q. A$ f. j+ C2 l这些事项如何体现到程序中请参照示例代码文件并结合视频教程学习。这样的并行办法简单易行,对原始程序没有太大的改动,同时传递变量耗费时间也较少,效率比较高。2 f0 U/ S! R5 f
另外一个问题就是并行代码做模拟的次数问题。我们要达到用非并行的代码做N此模拟所能得到结果的精确程度,在核心为CoreNum并行代码中,Parfor语句段中只要做N/CoreNum次即可达到。9 h! A0 h5 Z0 F* B" S5 ?! e
: Z" z$ L8 H2 E+ _1 I; [5 s
五、将例子改写为并行代码& {8 R: l4 {& n) C7 C1 Y
附件中的pareg1.m,……,pareg5.m五个文件分别是前一章五个例子的并行代码。这里需要提到的是,这五个代码文件都是用向量化的代码编写。原因在于,在前一章大家都看到了,向量化的代码比循环语句代码一般快几十甚至上千倍,所以要提高速度,向量化代码是最重要的优化方法,并行计算倒是其次。
( E8 p5 c. c1 @3 W" A; {, S
5 M/ T9 U: X1 P* e%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%4 }' t* V; u' T7 D5 G3 b: d8 x0 H: H/ r
由于要搜索多核运行,找到这个帖子里来了/ V( f% n% I: G8 |9 X' ?
& h+ q! V' `. h3 h0 O' F- X2 a
刚才试了一下,我使用的MATLAB2010可以多核运行的。需要多核多线程跑的算法,在之前要让matlab在本地建立4个“实验室”(我的机器是4核,所以是4个)
, n8 O y' |7 `6 F+ p* d>> matlabpool local 4
) @- W9 z* {3 U. J' E+ @Starting matlabpool using the 'local' configuration ... connected to 4 labs.: q. I6 n0 [& b( ]5 a
显示正在进行多核配置,一会说,连接到4个“实验室”。我理解就是在本地虚拟出4台可以运行matlab的工作站,这样用分布式计算工具箱可以进行并行计算(matlabpool这个命令好像是在并行计算工具箱里的)。观察windows任务管理器,可以发现一共有5个MATLAB.exe进程。其中一个占内存较多的,我理解是主控的,他基本不干活,只负责分配,进行计算时他的cpu占用率只有1~2%,剩下四个进程专门用来计算的,跑起来各占cpu 25%左右。看上去还是每个matlab进程单核运算,但是一下开4个进程,所以能把cpu用满。
: f' `0 z1 Z3 x+ p0 p+ _4 A如果后续还需要多核运算,就直接用parfor好了,不用每次都用matlabpool命令。那个配置一次就好。3 J: s6 m) B; R
算完了,不再跑了,临退出时关闭配置就行。
. ?& ^6 K! c5 C>> matlabpool close5 B# q/ s3 S/ p# B
Sending a stop signal to all the labs ... stopped.. e' G- j) J# U' P* V0 q
) J! g* F' S7 N$ J" n2 Y下面是我一个M文件的程序,测测4核并行计算和单核计算的差距,很简单。/ U7 W( ]" Z9 K6 V) B8 ^7 d
function testtime* m6 v8 }: V; |4 @
3 N4 v; ? W2 K5 druntimes = 1e9;
. l1 X7 m$ U% p7 C O/ wdummy1 = 0;
& c. e& ]- `9 J7 adummy2 = 0;
6 }5 D: i5 x1 h' e6 ?$ O' D% V: ?7 i1 o' T
%matlabpool local 46 }# E6 m0 v. ?$ K/ s0 |* l+ G. k
_0 d o. T0 m4 f U
tic8 a0 h2 ]* H+ S2 _
%for x= 1:runtimes;5 z4 F' [) L' p. U
parfor x= 1:runtimes;
5 O) @8 n3 j+ W; c dummy1 = dummy1 + x;
" `# G# a/ {5 P/ L( s dummy2 = 2 * x + 1;5 v, Q" I0 f' c M9 l, L
end
* }, N4 u7 k% @* `8 Z; Vtoc
& ]0 G- h I; s% X* [" f/ G
3 J3 G4 t- ]1 a1 ? y' o3 i0 `3 bplot([1 2], [dummy1, dummy2]);+ S6 E. _& }+ k3 c
8 Q: W- ^ ]& }
第一次用普通for语句,单核跑,6.09秒) h" M _. m, ], c5 Y1 `
>> testtime& r2 D. Z! ?4 I- {9 `
Elapsed time is 6.094267 seconds.
/ k4 D8 q6 l8 e* @" D( B
6 \* G |9 n- I9 y第二次用parfor语句,4核跑,1.63秒0 K) r& G7 k' @$ e% [$ R6 K* R2 Q
>> matlabpool local 4
- p! k$ B$ K( L& n8 [! A8 wStarting matlabpool using the 'local' configuration ... connected to 4 labs.
7 B- g$ _& [: w' N! q>> testtime) M1 v% F& |- J7 }5 d2 r
Elapsed time is 1.631350 seconds./ n F% W7 W$ i: S5 ?6 X- S( w
>> matlabpool close3 I$ \; E# \. o+ s) \& H
' Z' a2 ?$ P! V% o( ]" G加速比 6.09 / 1.63 = 3.736,将近4倍(还有开销吧),还比较可观。" }- o5 s: B! b
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 _9 ~% x1 ^ C6 k2 K1 x 0 w) h' Z9 i$ e/ Y- |
然后说一下要注意的几个问题:' o/ a3 F6 w9 j* p8 V- @4 f1 x
1、parfor效果好,但是用起来要注意程序的细节。很多地方都会报错。比如下标必须为连续的整数!否则会报下面这个错误“The variable xxx in a parfor cannot be classified.”具体可以看parfor帮助文件里面的sliced variables这一节,帮助建议仔细全部看过最好。9 {2 D+ H& I; M" J8 H6 o! d$ j7 Z
2、用了parfor之后,输出参数用nargout确定,会出错。不知道为什么。( k# O `# P" t' X! H1 H6 N
3、变量在parfor内外的传进传出要非常小心,因为并行的关系,依赖循环下标的变量都要仔细考虑。" s0 `2 x& w6 M& ]: o& B
@& K. P; q5 v, \% |* o在程序里面,用profile监测,3 C, {2 U. @ @: W7 j
不用并行计算的时候,CPU时间为 84.742 S,
$ g$ [8 q! P! E( u' t) d用了并行计算的时候,CPU时间为 15.231 S) @8 R/ z' p0 W% G# V% r8 {
加速比达到了5.6!!!!!!" w2 ], Y& s- m5 H9 \$ E/ C1 w
8 G6 f; W }/ h0 b1 f
6 e- y2 X& T. V- |( _- n |
|