【问题标题】:How to broadcast a message to a list of processes in Erlang?如何将消息广播到 Erlang 中的进程列表?
【发布时间】:2014-11-29 13:04:12
【问题描述】:

我是 Erlang 的新手,我正在尝试了解如何将消息从一个进程发送到进程列表。

假设我们有一个包含 Pid 列表的数据结构。如何让 Pid 向 Pid 列表发送消息“M”,其中列表的每个元素都有 2 个元素:字符串(代表名称)和 Pid? 我想出的是:

broadcast(P, M, R) ->
  P ! {self(), friends},
  receive
    {P, Friends} ->
  P ! {self(), {send_message, {M, R, P, Friends}}}
  end.

looper({Name, Friends, Messages}) ->
{From, {send_message, {M, R, ID, [{FriendPid, FriendName} | FriendTale]}}} ->
  if R =< 0 ->
        From ! {From, {self(), {ID, M}}},
        looper({Name, [{FriendPid, FriendName} | FriendTale], [{ID, M} | Messages]});
     R > 0  andalso FriendTale =/= []->
       FriendPid ! {From, {send_message, {M, R-1, ID, FriendTale}}},
       looper({Name, FriendTale, [{ID, M} | Messages]})
  end;
 terminate ->
    ok
end.

但据我了解,我没有正确匹配 Pid 列表的模式,因此我可以从 Pid 列表的元素中“提取” Pid。

基本上,我有一个名为“looper”的函数,它不断等待新消息的到达。当它收到类型为

的消息时
{send_message, {M, R, ID, [{FriendPid, FriendName} | FriendTale]}}

其中“M”是我想向名为“Friends”的 Pid 列表广播的消息,而 R 只是一个整数。

R 基本上是一个整数,表示消息应该走多远。

e.g. 0 = broadcast the message to self,
     1 = broadcast the message to the friends of the pid,
     2 = broadcast the message to the friends of the friends of the pid and so on...

设置 Pid 并设置 Pid 之间的“友谊”后,我从终端得到的是:

1> f().
ok
2> c(facein).
facein.erl:72: Warning: variable 'From' is unused
{ok,facein}
3> {Message, Pid} = facein:start({"Bjarki", [], []}).
{ok,<0.186.0>}
4> {Message, Pid2} = facein:start({"Bjarki2", [], []}).
{ok,<0.188.0>}
5> facein:add_friend(Pid,Pid2).
ok
6> facein:broadcast(Pid,"hello",1).

=ERROR REPORT==== 5-Oct-2014::12:12:58 ===
Error in process <0.186.0> with exit value: {if_clause,[{facein,looper,1,[{file,"facein.erl"},{line,74}]}]}

{<0.177.0>,{send_message,{"hello",1,#Ref<0.0.0.914>}}}

任何帮助将不胜感激。 谢谢

【问题讨论】:

  • 您能否添加loop 定义(您的论点如何准确命名)。
  • @mpm ok 添加了looper定义
  • 您可以考虑使用gproc,它有一个方便的Pub/Sub module,可以让您订阅一个事件的进程,然后向该事件的所有订阅者发布消息。

标签: erlang erlang-shell


【解决方案1】:

编辑

添加广播功能后。您收到的发送到looper 功能的是friends atom。你不能对原子做列表理解,只能在列表上。这就是为什么当您尝试使用 &lt;- 运算符时会得到 bedarg 的原因。

打破您的逻辑:您将 pid 和 atom 发送给自己,只是为了稍后收到一行。不知道你为什么需要这样做?您可以直接使用基本相同的方法:

broadcast(P, M, R) ->
  P ! {self(), {send_message, {M, R, P, friends}}}.

现在您可以清楚地看到,您发送给looper的是原子,而不是pid列表。


你得到的错误提示你正在调用一些类型错误的内置 Erlang 函数(+!)。所以我猜Friends 之一不是进程,或者R 不是你可以- 1 上的东西。也许尝试在列表理解之前将它们打印出来以进行调试。

你也可以使用像

这样的守卫
receive
  {From, {send_message, {M, R, ID, Friends}}} when is_integer(R) ->
     %%  ...

但您只会忽略模式不匹配的消息。

小笔记

我不确定您是否正在尝试这样做,但这些也可能会有所帮助。

我能注意到的一件事是您正在发送元组 {send_message, {M, R-1, ID, Friends}}。这就是你的全部信息,只有这个会被接收。 Erlang 不会神奇地添加任何东西,所以如果你指望接收 {From, {send_message, {M, R, ID, Friends}}} ,你需要自己发送这个 From 。赞这个F ! {self(), {send_message, {M, R-1, ID, Friends}}}

您可能要注意的另一件事是“更长”函数中的模式匹配。 Friends 变量被绑定(分配给一个值)作为函数参数。因此,当您在做receive {From, {send_message, {M, R, ID, Friends}}} 时,您正在做的是消息类型(二元组,二元组和四元组)的模式匹配,原子send_message Friends列表。这意味着只有当您收到与最初调用 loop 函数完全相同的朋友列表时,您才会执行“发送逻辑”。并且所有其他消息(当然除了terminate)将被忽略(只会留在您的消息框中)。如果您指望结交一些新朋友,请对未绑定的变量进行模式匹配(保持函数简短有助于此 Erlang-gotcha)。

【讨论】:

  • 感谢您的回复,但我重新编辑了我的问题以使其更清楚:) 我希望这会有所帮助。谢谢你的时间。
  • 我添加了完整的循环器,以防它的其他部分出现问题。我还更好地解释了每个变量是什么。 :)
猜你喜欢
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多