为啥第二次调用接收没有在 Erlang shell 中检索消息?

Posted

技术标签:

【中文标题】为啥第二次调用接收没有在 Erlang shell 中检索消息?【英文标题】:Why second call to receive doesn't retrieve a message in Erlang shell?为什么第二次调用接收没有在 Erlang shell 中检索消息? 【发布时间】:2020-06-08 17:23:21 【问题描述】:

我正在使用 Erlang 中的进程并尝试创建一个简单的计数器进程。 它接收发送者的 PID,增加内部计数器并将新的计数器值发送给发送者。 我从 erl shell (Erlang/OTP 20, Eshell V9.2) 启动我的代码。 而且我能够成功收到来自计数器进程的第一个回复,但不是第二个。

%% Process function that serves as a counter
CounterFun = fun() ->
  (fun Receiver(Current) ->
    io:format("  -- Entering receiver, current ~p~n", [Current]),
    receive
      Sender ->
        New = Current + 1,
        io:format("  -- Sending ~p to ~p~n", [New, Sender]),
        Sender ! New,
        Receiver(New)
    end
  end)(0)
end.

CounterPid = spawn(CounterFun).

CounterPid ! self().
receive V -> V after 3000 -> timeout end. % Will provide 1

CounterPid ! self().
receive V -> V after 3000 -> timeout end. % Will result in timeout

这是在我的控制台中的样子。

【问题讨论】:

【参考方案1】:

第一次接收将变量V绑定到1,所以第二次接收变为:

receive 
    1 -> ...

end

而且,由于消息1 从未到达,第二次接收超时。超时后,可以在shell中调用flush(),会看到邮箱中有2的消息。您也可以随时调用b() 来显示当前变量及其值(称为绑定)——在执行第一次接收后尝试。

在您的函数中,您还在接收中的接收中执行递归接收,这样第一次接收永远不会结束。为了证明这一点,你可以在后面加上一个 print 语句:

Receiver(New)

喜欢:

io:format("receive ending with Current= ~w~n", [Current])

你将永远看不到任何输出。你应该把你的接收改成这样:

New = Currrent + 1
receive
  Sender ->
    io:format("  -- Sending ~p to ~p~n", [New, Sender]),
    Sender ! New,
    io:format("receive ending with Current= ~w~n", [Current])
end,
counter(New).

【讨论】:

以上是关于为啥第二次调用接收没有在 Erlang shell 中检索消息?的主要内容,如果未能解决你的问题,请参考以下文章

为啥套接字关闭 Erlang

为啥第二次调用 glBindBuffer?

为啥在 C++ 中第二次调用析构函数未定义的行为?

为啥当android在java中调用第二次Web服务时会创建新的会话

为啥函数第一次调用比第二次和第三次调用花费更多的时间等等?

为啥我的 ViewController 在第二次调用后才发布,iOS ARC?