【问题标题】:In Erlang is there any way that a message sender can wait on a response?在 Erlang 中有什么方法可以让消息发送者等待响应?
【发布时间】:2011-01-19 17:49:21
【问题描述】:

在 Erlang 中,消息发送者有什么方法可以等待响应,因此只有在处理完消息后才会继续执行?

我的意思是这样的:

Actor ! DoSomething
Continue to this next line of code when DoSomething has been processed

我知道可以通过发送发送者的Pid来进行回调,但是还有其他方法可以等待吗?

【问题讨论】:

  • ...你为什么想要那个?它不是违背了 Erlang 的全部目的吗?
  • 您确实应该考虑阅读文档并进行试验,而不是让 StackOverflow 充满您感到困惑的所有内容。这包含在 OTP 设计原则文档中。如果你没有使用 OTP 设计原则,那是因为你对 erlang 的理解足够好,不会问这样的问题。
  • 达斯汀,你可能会觉得这很难相信,但并不是每个人都像你一样聪明。也许我们也需要 smartoverflow.com :)
  • @Zubair,这与聪明无关。这是关于尝试自己而不是利用别人的时间。几乎你所有的问题都是可以在 50 秒和 10 秒的思考过程中搜索到的东西。请停止用这些问题淹没 stackoverflow,因为你不想自己做你的工作。
  • 我不知道该说什么。我做谷歌并尝试研究答案。我想你是对的,但你必须记住,我不是一个技术型的人,所以你可能从在线文档中理解的东西对于 99.99% 的人来说都是胡言乱语,不幸的是我是那 99.99% 的人之一。我知道 StackOverflow 只有 600 万成员,而且他们可能在前 00.01% 中,而且都是技术人员。也许我是这个网站的错误人群。但我也想问,有没有适合像我这样技术比你低很多的人的网站?

标签: erlang pid actor


【解决方案1】:

首先要了解的是,Erlang 是为处理异步消息传递而构建的。因此,同步消息传递的唯一方法是实现类似于确认的东西。

想象两个进程,P1 和 P2。 P1 可能会运行以下代码:

%% process P1 takes the Pid of P2 as a parameter
%% and a Message to pass on to P2
p1(P2, Message) ->
    P2 ! {self(), Message},
    receive
        {P2, ok}
    after 5000 -> % this section is optional, times out after 5s
        exit("P2 didn't process this!") % this kills P1
    end.

P2 可能只是运行以下命令:

p2() ->
    receive
        {From, Message} ->
            io:format("P2 received message ~p~n",[Message]),
            %% processing is done!
            From ! {self(), ok}
    end.

那么你可能会生成 p2 作为一个新进程。这个会坐等任何消息。然后,当您调用 p1 时,它会向 P2 发送一条消息,然后 P2 对其进行处理 (io:format/2) 并回复 P1。因为 P1 正在等待回复,所以在该进程中没有运行其他代码。

这是实现阻塞调用的基本且唯一的方法。使用gen_server:call 的建议大致实现了我刚刚展示的内容。不过,它对程序员是隐藏的。

【讨论】:

    【解决方案2】:

    您可以使用 receive 块:

    http://www.erlang.org/doc/reference_manual/expressions.html#id2270724

    阅读文档:

    接收永远不会失败。执行是 暂停,可能无限期, 直到消息到达 匹配其中一个模式并与 真正的保护序列。

    换句话说,发送消息并等待回复。

    【讨论】:

    • 希望某处有超时 ;-)
    • 这不是发送 Pid 并等待接收吗?这不是让它成为回调吗?我自己也不确定,所以请有人帮我解释一下。
    • @Zubair:如果你说“你好!”你会等我的“你好!”我回答“你好!”。有回调吗?这就是 Erlang 的工作方式。只是进程和消息。你是进程,我是进程。你发消息,我发消息。我收,你收。这里没有回调。
    • 好的,谢谢@Hynek。我想我误解了什么是回调。
    【解决方案3】:

    如果接收进程是gen_server,可以使用gen_server:call。例如:

    gen_server:call(Pid, Message),
    % At this point, we know that the other process has answered.
    

    【讨论】:

    • 我很好奇有多少现实世界的应用程序是用这种技术构建的。
    • @jldupont。你问了一个有效的问题,我不确定答案是什么。不过我会这么说:如果你在 Erlang 上构建一个重要的系统,那么你可能应该使用 OTP,因此应该使用 gen_server:call()。如果您不使用 OTP,那么您最终会重新发明 OTP 为您所做的一些事情,或者以不发挥 Erlang 优势的方式编写代码......在这种情况下,您可能应该使用首先是一种不同的语言。
    • @Tim:更准确地说:我很好奇 gen_server:call() 与异步 gen_server:cast() 对应物相比有多受欢迎。
    • call 可用于代理任何类型的资源、控制服务器的状态、从服务器请求数据、基于服务器的负载调节......
    • gen_server:call 最大的优点是,您可以通过立即返回 noreply 来阻止调用者,同时通过生成处理调用并从那里返回回复的进程来保持并行性。尝试在 java 中执行此操作(轻松)。很抱歉最后的评论,但我想自己把它拿出来,并向这个小小的金色图案 erlang(公平地说,OTP)免费提供给我......
    【解决方案4】:

    不,只有异步消息传递。

    如果您想有点哲学,那么很难自动定义何时处理消息。是在消息到达进程时,已接收但尚未采取行动,还是在接收进程已采取行动时。这类似于当有人“阅读”我的邮件时收到自动通知。是的,他们看过但他们真的读过?

    【讨论】:

      【解决方案5】:

      仅取决于 jldupont 的情况。如果 web 浏览器向 webmachine 请求一些长期运行的 erlang 资源,则无法使用强制转换来满足该请求。

      【讨论】:

        猜你喜欢
        • 2014-01-15
        • 1970-01-01
        • 2021-10-13
        • 2012-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-21
        • 1970-01-01
        相关资源
        最近更新 更多