如何在Erlang中处理动态注册的进程和模式匹配



当我向原子注册进程时,我可以通过原子而不是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. 请注意我是如何将最后一个循环/1调用移到接收块之外的函数末尾的。Erlang确实对编译时的尾部调用进行了优化,所以您的代码应该很好,但最好显式地进行尾部调用,这样可以帮助您避免错误。

  2. 您可能正在尝试重新发明gen_servergen_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>

最新更新