当我向原子注册进程时,我可以通过原子而不是Pid交换发送消息,这很方便。然而,模式匹配似乎将Pid和atom视为不同的实体,这是意料之中的,但并不方便。在我的示例中,{Pid, Response}
模式不匹配,因为此范围中的Pid
是一个原子,但作为响应发送的消息包含实际的Pid。
有没有一种更可取的方法来处理这个问题?
程序:
-module(ctemplate).
-compile(export_all).
start(AnAtom, Fun) ->
Pid = spawn(Fun),
register(AnAtom, Pid).
rpc(Pid, Request) ->
Pid ! {self(), Request},
receive
{Pid, Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{Pid, Any}])
end.
loop(X) ->
receive
{Sender, Any} ->
io:format("Received: ~p~n",[{Sender, Any}]),
Sender ! {self(), "Thanks for contacting us"},
loop(X)
end.
外壳:
Eshell V5.10.2 (abort with ^G)
1> c(ctemplate).
{ok,ctemplate}
2> ctemplate:start(foo, fun() -> ctemplate:loop([]) end).
true
3> ctemplate:rpc(foo, ["bar"]).
Received: {<0.32.0>,["bar"]}
Finish (wrong):{foo,{<0.40.0>,"Thanks for contacting us"}}
ok
4> whereis(foo).
<0.40.0>
请改用引用。您所建议的示例实际上是refs更适合同步消息的原因之一。另一个原因是,有时您无法保证收到的消息是您实际期望的消息。
所以,你的代码看起来像
rpc(PidOrName, Request) ->
Ref = make_ref(),
PidOrName ! {{self(), Ref}, Request},
receive
{{Pid, Ref}, Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{PidOrName, Any}])
end.
loop(X) ->
receive
{{Pid, Ref}, Any} ->
io:format("Received: ~p~n",[{Sender, Any}]),
Sender ! {{self(), Ref}, "Thanks for contacting us"},
end,
loop(X).
关于您和我的代码的几条注释:
请注意我是如何将最后一个循环/1调用移到接收块之外的函数末尾的。Erlang确实对编译时的尾部调用进行了优化,所以您的代码应该很好,但最好显式地进行尾部调用,这样可以帮助您避免错误。
您可能正在尝试重新发明
gen_server
。gen_server:call/2
和我上面的代码之间仅有的两个主要区别是超时(gen_server
有超时(,以及引用是通过监视远程进程创建的。这样,如果进程在抛出超时之前死亡,我们将立即收到一条消息。在许多情况下,它的速度较慢,但有时会证明它很有用。
总体而言,请尝试使用OTP并读取其代码。它很好,可以让您更好地了解Erlang应用程序应该如何工作。
rpc(Pid, Request) ->
Pid ! {self(), Request},
receive
{whereis(Pid), Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{Pid, Any}])
end.
您可以使用whereis()
:
其中is(RegName(->pid((|port((|未定义的
Types:
RegName = atom()
Returns the pid or port identifier with the registered name RegName. Returns undefined if the name is not registered.
例如:
其中为(db(。
<0.43.0>