N-Queens / Erlangを並列化
した。おとといのC++版と同じ戦略で。とても簡単 :-)
プログラムはすぐ並列化できたけど、Mac PortsでインストールしたErlangがsmpに対応してないでやんの。
仕方が無いので、ソースをダウンロードしてきて、再make orz
% ./configure --enable-smp-support
% make
でOK。
で、実行してみると、答えはあってるし、大体半分くらいの時間で終わるんだけど、計測した時間が変?
逐次版で、1122とかでるところが、並列版でも1182とかでるし、たまに4098とか出る。timer:tcでの計測は駄目?
ググって、
go(N)-> T1 = erlang:now(), Res = count(qu(N)), T2 = erlang:now(), Time = timer:now_diff(T2, T1), {Time,Res}.
とかやってる人を見つけたので、これで計測。
すると、
- 逐次版:10179827とか:10秒ってところか?
- 並列版:5783055とか:5.7秒くらい?
というわけで、まずまず。(時計の秒針を見ての)体感もこれくらいだから、あってるんだろう、多分。
並列化した(=spawnを使った)プログラムは下記の通り。別に大した差はないです。
関数の引数にself()で取得した自プロセスのPidを渡してspawnし、spawnされたプロセスは結果を引数のPidで示されるプロセスに"!"で送ります。spawnした方のプロセスは、結果が欲しい時点で、receiveを使って計算結果をもらうと。
-module(qupar). -export([qu/1, qudist/4, go/1, count/1]). %go(N) -> timer:tc(qu,count,[qu(N)]). go(N)-> T1 = erlang:now(), Res = count(qu(N)), T2 = erlang:now(), Time = timer:now_diff(T2, T1), {Time,Res}. count(C) -> count(C,0). count([_H|T],Crnt) -> count(T,Crnt+1); count([],Crnt) -> Crnt. append([A|X],Y) -> [A|append(X,Y)]; append([],Y) -> Y. qu(N) -> spawn(qupar,qudist,[generate(N), [], [], self()]), receive Ans -> Ans end. generate(N) -> if N > 0 -> [N|generate(N - 1)]; N == 0 -> [] end. qudist([P|Lu],Ls,Lp,Pid) -> spawn(qupar,qudist,[Lu,[P|Ls],Lp,self()]), Lr = append(Lu,Ls), Ans1 = check(P,1,Lr,Lp,Lp), receive Ans2 -> Ans = append(Ans1, Ans2) end, Pid ! Ans; qudist([],[_|_],_,Pid) -> Pid ! []; qudist([],[],Lp,Pid) -> Pid ! [Lp]. qu([P|Lu],Ls,Lp) -> Lr = append(Lu,Ls), Ans1 = check(P,1,Lr,Lp,Lp), Ans2 = qu(Lu,[P|Ls],Lp), append(Ans1, Ans2); qu([],[_|_],_) -> []; qu([],[],Lp) -> [Lp]. check(P,D,L,[Q|Lp0],Lp) -> if (Q + D == P) or (Q - D == P) -> []; true -> D1 = D + 1, check(P,D1,L,Lp0,Lp) end; check(P,_,L,[],Lp) -> qu(L,[],[P|Lp]).