这里面有两种方法,核数为2的幂见代码1,核数不为2的幂见代码2.
代码1:
-module(exe5_2).
-export([start/2]).
%Points 是投掷点的个数 Cores是核数,为2的幂
start(Points,Cores)
->spawn(fun()->parent_proces(Points,Cores) end),
io:format("").
parent_proces(Points,Cores) ->
PointsPerProcess = Points div Cores,
creat_child_proces(Points,PointsPerProcess,Cores,Cores,[]).
%创建子进程
creat_child_proces(Points,PointsPerProcess,Cores,N,L)
when N =:=1 ->
Pid = spawn(fun()->process_points(Points,Points-PointsPerProcess*(Cores-1)) end),
Father = self(),
PidR = spawn(fun()->loop_control(Father,0,Cores,2) end),
sendInfo(L++[Pid]++[PidR],1,Cores,2,Cores);
creat_child_proces(Points,PointsPerProcess,Cores,N,L)
->Pid=spawn(fun()->process_points(Points,PointsPerProcess) end),
creat_child_proces(Points,PointsPerProcess,Cores,N-1,L++[Pid]).
%计算命中的点
process_points(Points,PointsPerProcess) ->
apply(random, seed, tuple_to_list(now())),
Count = test_points(PointsPerProcess, 0),
io:format("~p 's result is ~p~n",[self(),Count]),
loop_send_get(Points,Count).
test_points(0, Count) -> Count;
test_points(PointsPerProcess, Count) ->
X = (random:uniform() * 2) - 1,
Y = (random:uniform() * 2) - 1,
I = X*X + Y*Y,
if
I < 1 ->
test_points(PointsPerProcess - 1, Count + 1);
true ->
test_points(PointsPerProcess - 1, Count)
end.
%子进程部分和的发送和接收,由主进程sendInfo方法控制
loop_send_get(Points,Sum) ->
receive
{From,Sum1,Father,PidR} ->
io:format("~p from ~p to ~p result is ~p ~n",[Sum1,From,self(),Sum1+Sum]),
PidR!{"ok"},
loop_send_get(Points,Sum+Sum1);
{Pid,Father,PidR} ->
Pid!{self(),Sum,Father,PidR};
{"getRes"} ->Res=(Sum/Points)*4,
io:format("Pi:~p~n",[Res])
end.
%控制每一轮迭代求和的次数,N为一轮迭代中求和的次数,初始值为0,Divisor为控制变量,初始值为2
loop_control(Father,N,Cores,Divisor) ->%io:format("N:~p Divisor:~p~n",[N,Divisor]),
if
Cores =:= N*Divisor ->
Father!{self(),"over"},
loop_control(Father,0,Cores,Divisor*2);
true ->
receive
{"ok"} -> loop_control(Father,N+1,Cores,Divisor)
end
end.
sendInfo(PidList,N,Cores,Divisor,Dsum) ->%io:format("Pidlist:~p ~nN:~p Cores:~p Divisor:~p Dsum:~p ~n",[PidList,N,Cores,Divisor,Dsum]),
Nt = erlang:trunc(N),
if
Divisor =:= 2*Dsum -> Pid_1=lists:nth(1,PidList),
Sum=Pid_1!{"getRes"};
Nt > Cores ->
receive
{From,"over"} ->sendInfo(PidList,1,Cores-Divisor/2,Divisor*2,Dsum)
end;
Nt rem Divisor =:= 1 ->
sendInfo(PidList,N+Divisor/2,Cores,Divisor,Dsum);
Nt rem Divisor =/= 1 ->
Pid_send = lists:nth(Nt,PidList),
Pid_get = lists:nth(erlang:trunc(Nt-Divisor/2),PidList),%io:format("send:~p get:~p~n",[Pid_send,Pid_get]),
Pid_send!{Pid_get,self(),lists:nth(erlang:trunc(Dsum+1),PidList)},
sendInfo(PidList,N+Divisor/2,Cores,Divisor,Dsum)
end.
代码2:
-module(exe5_4).
-export([main/2]).
%Points投掷点的总数 Core为核数,任意值
main(Points,CoreNum) ->
SumDie=temp(CoreNum,1),
PointsPerProcess = Points div CoreNum,
createP(1,CoreNum,SumDie,Points,PointsPerProcess),
io:format("").
temp(Num,SNum) when Num =< SNum -> SNum;
temp(Num,SNum) -> temp(Num,SNum*2).
createP(N,CoreNum,SumDie,Points,PointsPerProcess) when N =:= CoreNum ->
register(integer_to_atom(N),spawn(fun()->process_points(Points,N,2,CoreNum,SumDie,Points,Points-PointsPerProcess*(CoreNum-1)) end));
createP(N,CoreNum,SumDie,Points,PointsPerProcess) ->
register(integer_to_atom(N),spawn(fun()->process_points(Points,N,2,CoreNum,SumDie,Points,PointsPerProcess) end)),
createP(N+1,CoreNum,SumDie,Points,PointsPerProcess).
integer_to_atom(Int) -> T=integer_to_binary(Int),
binary_to_atom(T,utf8).
%计算命中的点
process_points(Points,N,Die,CoreNum,SumDie,Points,PointsPerProcess) ->
apply(random, seed, tuple_to_list(now())),
Count = test_points(PointsPerProcess, 0),
io:format("~p 's result is ~p~n",[self(),Count]),
loop(Points,N,Die,SumDie,CoreNum,Count).
test_points(0, Count) -> Count;
test_points(PointsPerProcess, Count) ->
X = (random:uniform() * 2) - 1,
Y = (random:uniform() * 2) - 1,
I = X*X + Y*Y,
if
I < 1 ->
test_points(PointsPerProcess - 1, Count + 1);
true ->
test_points(PointsPerProcess - 1, Count)
end.
%每个core 收发信息
loop(Points,Number,Die,SumDie,CoreNum,Count) ->
if
Die =:= SumDie*2 -> Res = (Count/Points)*4,
io:format("Pi=~p~n",[Res]);
true -> [H|L]=judge(CoreNum,Number,Die),
if
H =:= 1 -> [H2|_]=L,
{send,To,DieThat}=H2,
(integer_to_atom(To))!{Number,DieThat,Count};
true -> [H2|_]=L,
{get,From,DieThat}=H2,
receive
{From,DieThat,Count1} -> io:format("~p ~p get info from ~p,the result is ~p~n",[Count1,Number,From,Count+Count1]),
loop(Points,Number,Die*2,SumDie,CoreNum,Count1+Count)
end
end
end.
%判断每核的收发
judge(SumCore,Number,Die) -> R=lslast(SumCore,Number,Die),
if
R =:= 1 ->
if
Number rem Die =:= 1 -> {DieThat,To}=find(Number,Die),
[1,{send,To,DieThat}];
true -> [1,{send,Number-erlang:trunc(Die/2),Die}]
end;
true ->
if
Number rem Die =:= 1 -> [0,{get,Number+erlang:trunc(Die/2),Die}];
true -> [1,{send,Number-erlang:trunc(Die/2),Die}]
end
end.
%判断最后一核信息发送给哪里
find(Number,Die) -> Current_order=ceil(Number*2/Die),
if
Current_order rem 2 =:= 0 -> {Die,Number-erlang:trunc(Die/2)};
true -> find(Number,Die*2)
end.
%计算live的核在本轮迭代中的序号,若为最后一个标记为1.
lslast(SumCores,Number,Die) -> Current_order=ceil(Number*2/Die),
Sum_order=ceil(SumCores*2/Die),
io:format("~p ~p ~p ~p ~p~n",[SumCores,Number,Die,Current_order,Sum_order]),
if
Current_order =:= Sum_order -> 1;
true -> 0
end.
%对小数取上界,比如ceil(15.1)=16
ceil(N) -> T=trunc(N),
Temp = N-T,
case Temp =:= 0.000 of
true -> T;
false -> T+1
end.