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

如何在Erlang中处理动态注册的进程和模式匹配?,erlang,Erlang,当我向atom注册一个进程时,我可以通过atom而不是Pid交换地发送消息,这很方便。然而,模式匹配似乎将Pid和atom视为不同的实体,这是预期的,但并不方便。在我的示例中,{Pid,Response}模式不匹配,因为此范围中的Pid是一个原子,但作为响应发送的消息包含实际的Pid 有没有更好的方法来处理这个问题 该方案: -模块(ctemplate)。 -编译(全部导出)。 开始(安纳托姆,乐趣)-> Pid=繁殖(乐趣), 寄存器(AnAtom,Pid)。 rpc(Pid,请求)-> Pi

当我向atom注册一个进程时,我可以通过atom而不是Pid交换地发送消息,这很方便。然而,模式匹配似乎将Pid和atom视为不同的实体,这是预期的,但并不方便。在我的示例中,
{Pid,Response}
模式不匹配,因为此范围中的
Pid
是一个原子,但作为响应发送的消息包含实际的Pid

有没有更好的方法来处理这个问题

该方案:

-模块(ctemplate)。
-编译(全部导出)。
开始(安纳托姆,乐趣)->
Pid=繁殖(乐趣),
寄存器(AnAtom,Pid)。
rpc(Pid,请求)->
Pid!{self(),Request},
接收
{Pid,Response}->
反应;
任何->
io:format(“Finish(错误):~p~n”,[{Pid,Any}])
结束。
循环(X)->
接收
{发送方,任意}->
io:格式(“接收:~p~n”,[{发送方,任意}]),
发件人!{self(),“感谢联系我们”},
循环(X)
结束。
壳牌公司:

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>
Eshell V5.10.2(使用^G中止)
1> c(ctemplate)。
{好的,ctemplate}
2> ctemplate:start(foo,fun()->ctemplate:loop([])end)。
真的
3> ctemplate:rpc(foo,[“bar”])。
收到:{,[“条”]}
完成(错误):{foo,{,“谢谢联系我们”}
好啊
4> (福)在哪里。

改用引用。您建议的示例实际上是REF更适合同步消息的原因之一。另一个原因是,有时您无法保证收到的消息是您实际期望的消息

因此,您的代码看起来像

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调用从receive块移到函数末尾的。Erlang确实进行了编译时尾部调用优化,因此您的代码应该很好,但最好是显式地进行尾部调用,这样可以帮助您避免错误

  • 您可能正在尝试重新发明
    gen\u server
    gen\u server:call/2
    和上面我的代码之间唯一的两个主要区别是超时(
    gen\u server
    有超时),并且引用是通过监视远程进程创建的。这样,如果进程在抛出超时之前死亡,我们将立即收到一条消息。在许多情况下,它速度较慢,但有时证明它本身是有用的


  • 总的来说,尝试使用OTP并读取其代码。这很好,可以让您更好地了解Erlang应用程序应该如何工作。

    使用引用。您建议的示例实际上是REF更适合同步消息的原因之一。另一个原因是,有时您无法保证收到的消息是您实际期望的消息

    rpc(Pid, Request) ->
    Pid ! {self(), Request},
    receive
        {whereis(Pid), Response} ->
            Response;
        Any -> 
            io:format("Finish (wrong):~p~n",[{Pid, Any}])
    end.
    
    因此,您的代码看起来像

    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调用从receive块移到函数末尾的。Erlang确实进行了编译时尾部调用优化,因此您的代码应该很好,但最好是显式地进行尾部调用,这样可以帮助您避免错误

  • 您可能正在尝试重新发明
    gen\u server
    gen\u server:call/2
    和上面我的代码之间唯一的两个主要区别是超时(
    gen\u server
    有超时),并且引用是通过监视远程进程创建的。这样,如果进程在抛出超时之前死亡,我们将立即收到一条消息。在许多情况下,它速度较慢,但有时证明它本身是有用的


  • 总的来说,尝试使用OTP并读取其代码。这很好,可以让您更好地了解Erlang应用程序应该如何工作。

    使用引用。您建议的示例实际上是REF更适合同步消息的原因之一。另一个原因是,有时您无法保证收到的消息是您实际期望的消息

    rpc(Pid, Request) ->
    Pid ! {self(), Request},
    receive
        {whereis(Pid), Response} ->
            Response;
        Any -> 
            io:format("Finish (wrong):~p~n",[{Pid, Any}])
    end.
    
    因此,您的代码看起来像

    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调用从receive块移到函数末尾的。Erlang确实进行了编译时尾部调用优化,因此您的代码应该很好,但最好是显式地进行尾部调用,这样可以帮助您避免错误

  • 您可能正在尝试重新发明
    gen\u server
    gen\u server:call/2
    和上面我的代码之间唯一的两个主要区别是超时(
    gen\u server
    有超时),并且引用是通过监视远程进程创建的。这样,如果进程在抛出超时之前死亡,我们将立即收到一条消息。在许多情况下,它速度较慢,但有时证明它本身是有用的


  • 总的来说,尝试使用OTP并读取其代码。这很好,可以让您更好地了解Erlang应用程序应该如何工作。

    使用引用。您建议的示例实际上是REF更适合同步消息的原因之一。另一个原因是,有时您无法保证收到的消息是您实际期望的消息

    rpc(Pid, Request) ->
    Pid ! {self(), Request},
    receive
        {whereis(Pid), Response} ->
            Response;
        Any -> 
            io:format("Finish (wrong):~p~n",[{Pid, Any}])
    end.
    
    因此,您的代码看起来像

    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调用从receive块移到函数末尾的。Erlang确实进行了编译时尾部调用优化,因此您的代码应该很好,但最好是显式地进行尾部调用,这样可以帮助您避免错误

  • 您可能正在尝试重新发明
    gen\u server
    gen\u server:call/2
    和上面我的代码之间唯一的两个主要区别是超时(
    gen\u server
    有超时),并且引用是通过监视远程进程创建的。这样,如果进程在抛出超时之前死亡,我们将立即收到一条消息。在许多情况下,它速度较慢,但有时证明它本身是有用的

  • 总的来说,