我的工作环境是Erlang。 具有2个不同功能的进程是否可以在不同的功能中具有两个接收块。
receive
....
end.
request()
PID!(message)
%% Can i get the reply back here instead of the receive block above?
答案 0 :(得分:11)
是的,你可以有很多receive
个表达式。当评估一个时,它将从消息队列/邮箱中取出第一个匹配的消息(选择你的名字),剩下的就留给下一个receive
。使用Pid ! Message
语法(唯一的方法)发送消息是完全异步的,只是将消息添加到接收进程消息队列的末尾。 receive
是接收消息的唯一方法,即将它们从消息队列中取出。你永远不能把它们放回去。
在Erlang中没有内置的同步消息传递,它通过发送两条消息来传递:
“请求”流程向接收流程发送消息,然后进入receive
等待回复。
“接收”流程本身会在receive
中收到邮件,对其进行处理,将回复邮件发送回“请求”流程,然后进入receive
进行访问并等待下一条消息。
请记住,进程之间没有固有的连接,并且所有通信都是使用异步消息发送和receive
完成的。
因此,在回答您的第二个问题时:您可以仅在receive
表达式中获得回复。这是唯一的方法!
很抱歉有点迂腐,但Erlang没有块或语句。它是一种函数式语言,只有表达式,即使有时会忽略返回值,它总是返回一个值。
答案 1 :(得分:2)
当然,你可以。
使用send运算符(!)接收发送到进程的消息。该 模式模式与第一条消息顺序匹配 邮箱中的时间顺序,然后是第二个,依此类推。如果匹配 成功并且可选的保护序列GuardSeq是真的, 对应的Body进行评估。消耗匹配的消息, 从邮箱中删除,而在邮箱中删除任何其他邮件 邮箱保持不变。
以下代码来自supervisor2.erl
项目的rabbitmq
。它甚至使用嵌套的receive
语句。我在下面标记了嵌套receive
。
terminate_simple_children(Child, Dynamics, SupName) ->
Pids = dict:fold(fun (Pid, _Args, Pids) ->
erlang:monitor(process, Pid),
unlink(Pid),
exit(Pid, child_exit_reason(Child)),
[Pid | Pids]
end, [], Dynamics),
TimeoutMsg = {timeout, make_ref()},
TRef = timeout_start(Child, TimeoutMsg),
{Replies, Timedout} =
lists:foldl(
fun (_Pid, {Replies, Timedout}) ->
{Reply, Timedout1} =
receive %% attention here
TimeoutMsg ->
Remaining = Pids -- [P || {P, _} <- Replies],
[exit(P, kill) || P <- Remaining],
receive {'DOWN', _MRef, process, Pid, Reason} -> %%attention here
{{error, Reason}, true}
end;
{'DOWN', _MRef, process, Pid, Reason} ->
{child_res(Child, Reason, Timedout), Timedout};
{'EXIT', Pid, Reason} ->
receive {'DOWN', _MRef, process, Pid, _} ->
{{error, Reason}, Timedout}
end
end,
{[{Pid, Reply} | Replies], Timedout1}
end, {[], false}, Pids),
timeout_stop(Child, TRef, TimeoutMsg, Timedout),
ReportError = shutdown_error_reporter(SupName),
[case Reply of
{_Pid, ok} -> ok;
{Pid, {error, R}} -> ReportError(R, Child#child{pid = Pid})
end || Reply <- Replies],
ok.