我在Erlang中编写了一个简单的程序。它的任务是计算给定多项式2 * x ^ 2 + 3 * x + 5的值。并行计算2 * x ^ 2和3 * x两者,最后将这两个部分加在一起,5是添加,最后我们得到了结果。有一个函数计算2 * x ^ 2,第二个计算3 * x,最后一个计算最终结果。这是代码:
-module(count2).
-compile([export_all]).
%-export([f_main/0]).
%computes the value of the polynomial 2*x^2 + 3*x + 5
f_result() ->
{Arg1, Res_1} = receive
{f1, X1, Temp1} -> {X1, Temp1}
end,
Res_2 = receive
{f2, _, Temp2} -> Temp2
end,
Res = Res_1 + Res_2 + 5, %adds 5 to the result of 2*X^2+3*X
io:format("f(~p) = ~p~n",[Arg1, Res]),
f_result().
%when the line 14 was io:format("f(~p) = ~p~p,[X1, Res], the compilation error occured:
%variable 'X1' unsafe in 'receive'
f_2(PidWyn) -> %computes 2*X^2
receive
{f2, X} ->
Res = 2*math:pow(X,2),
PidWyn ! {f2, X, Res},
f_2(PidWyn);
{finish} ->
io:format("f_2 : finish~n")
end.
f_1(PidWyn) -> %computes 3*X
receive
{f1, X} ->
Res = 3*X,
PidWyn ! {f1, X, Res},
f_1(PidWyn);
{finish} ->
io:format("f_1 : finish~n")
end.
f_main() ->
PidW = spawn(?MODULE, f_result, []), %the process ID of the function that computes and displays the final result
Pid1 = spawn(?MODULE, f_1, [PidW]),
Pid2 = spawn(?MODULE, f_2, [PidW]),
L = [1,2,3,4,5],
[Pid1 ! {f1, X} || X <- L], %sends a series of messages to the function f_1
[Pid2 ! {f2, X} || X <- L], %sends a series of messages to the function f_2
Pid2 ! {finish},
Pid1 ! {finish},
PidW ! {finish}, %sends the message to the function f_result to make it stop
io:format("f_main : finish~n").
如您所见,f_result
函数逐个有两个receive
语句。第一个从f_1
函数接收元组,第二个从f_2
函数接收元组。之后,该函数显示结果并调用自身进行循环。
我想让f_result
函数接收{finish}
元组会告诉它停止工作(类似的解决方案在f_1
和f_2
函数中可见),但我无法正确放置所需receive
。我试着把
{Arg1, Res_1} = receive
{f1, X1, Temp1} -> {X1, Temp1};
{finish} -> io:format("f_result : finish~n"),
exit(0)
end,
但它产生以下输出:
f_main : finish
f_result : finish
f_1 : finish
f_2 : finish
ok
如果你能给我一些建议,我将不胜感激。
答案 0 :(得分:1)
输出不一定有任何问题。在Erlang中,消息是异步发送的,因此运行f_result
的进程可能比运行f_1
和f_2
的进程更早地处理消息。
顺便说一句,代替exit(0)
,您通常会写exit(normal)
来表示流程退出&#34;通常&#34;,而不是因为错误。这个惯例在少数地方依赖。例如,具有非normal
退出的进程也会导致链接进程退出,并且使用transient
主管策略,当且仅当退出原因不是时,才能使主管重新启动进程normal
。
答案 1 :(得分:0)
虽然您看到的输出并不一定意味着您的代码实际上存在问题。 Erlang中的所有消息都是异步的,只保留一个promise。从一个进程发送到另一个进程的两条消息如果到达则会以相同的顺序到达。
首先为什么输出没有告诉你任何事情。使用消息执行io
模块io:format/1,2,3
的IO操作。这意味着您将四个进程中的四条消息发送到io
服务器进程。 (在您的情况下,对于组长,默认情况下名为进程user
执行标准IO操作。)不保证这些消息按照您期望的顺序到达。所涉及的过程产生四对独立的过程。它们通常以相同的顺序到达,但您不能依赖它。
其次,从finish
进程到f_main
的{{1}}邮件存在类似问题。该消息可能并且可能会在f_result
和f_result
的结果之前到达f_1
进程。这将导致您在提议的解决方案中的第一次接收将提前完成您的f_2
。
解决方案是强制f_result
消息以正确的顺序到达输入。只有当它通过相同的路径,相同的过程对行进时才能完成。您必须通过finish
将finish
发送到f_result
。所以你可以这样做:
f_1
结果:
-module(count2).
-compile([export_all]).
%-export([f_main/0]).
%computes the value of the polynomial 2*x^2 + 3*x + 5
f_result() ->
{Arg1, Res_1} = receive
{f1, X, Temp1} -> {X, Temp1};
finish ->
io:format("f_result : finish~n"),
exit(normal)
end,
Res_2 = receive
{f2, _, Temp2} -> Temp2
end,
Res = Res_1 + Res_2 + 5, %adds 5 to the result of 2*X^2+3*X
io:format("f(~p) = ~p~n",[Arg1, Res]),
f_result().
f_2(PidWyn) -> %computes 2*X^2
receive
{f2, X} ->
Res = 2*X*X,
PidWyn ! {f2, X, Res},
f_2(PidWyn);
finish ->
io:format("f_2 : finish~n")
end.
f_1(PidWyn) -> %computes 3*X
receive
{f1, X} ->
Res = 3*X,
PidWyn ! {f1, X, Res},
f_1(PidWyn);
finish ->
PidWyn ! finish,
io:format("f_1 : finish~n")
end.
f_main() ->
PidW = spawn(?MODULE, f_result, []), %the process ID of the function that computes and displays the final result
Pid1 = spawn(?MODULE, f_1, [PidW]),
Pid2 = spawn(?MODULE, f_2, [PidW]),
L = [1,2,3,4,5],
[Pid1 ! {f1, X} || X <- L], %sends a series of messages to the function f_1
[Pid2 ! {f2, X} || X <- L], %sends a series of messages to the function f_2
Pid2 ! finish,
Pid1 ! finish,
io:format("f_main : finish~n").
请注意,只有> count2:f_main().
f_main : finish
f_1 : finish
f_2 : finish
f(1) = 10
f(2) = 19
ok
f(3) = 32
f(4) = 49
f(5) = 70
f_result : finish
和f(X) = Y
保证按此顺序显示,因为它们是来自同一f_result : finish
进程到f_result
io服务器的邮件。 (即使user
和f_main : finish
也可能出现反向顺序,因为shell内部的工作方式,但没有必要知道这个细节。你可能永远不会看到这种情况发生。)