【问题标题】:Is it possible to send a message to all child processes in elixir/erlang?是否可以向 elixir/erlang 中的所有子进程发送消息?
【发布时间】:2018-07-03 03:49:52
【问题描述】:

假设我在 elixir 中生成了多个子进程。

defmodule Child do
  def start(name) do
    receive do
      msg -> IO.puts "Message received by #{name}: #{inspect msg}"
    end
  end
end

defmodule Parent do
  def main do
    child1 = spawn_link (fn -> Child.start("1") end)
    child2 = spawn_link (fn -> Child.start("2") end)
    child3 = spawn_link (fn -> Child.start("3") end)
  end
end

我是否可以向当前进程(或其他进程)的所有子进程发送消息?

send_to_children self(), "hello to all children"

例如,我可以通过某种方式告诉运行时向链接到当前进程的所有进程广播消息吗?我当然可以将所有生成的 pid 存储在某种数据结构中并循环执行此操作,但如果有某种规范的方法来执行此操作,它似乎会更有效且不易出错。

【问题讨论】:

    标签: erlang elixir message-passing


    【解决方案1】:

    由于您使用的是spawn_link,您可以获取所有链接进程的列表并向它们发送消息:

    defmodule Child do
      def start(name) do
        receive do
          msg -> IO.puts "Message received by #{name}: #{inspect msg}"
        end
      end
    end
    
    defmodule Parent do
      def main do
        child1 = spawn_link (fn -> Child.start("1") end)
        child2 = spawn_link (fn -> Child.start("2") end)
        child3 = spawn_link (fn -> Child.start("3") end)
        {:links, links} = Process.info(self, :links)
        for pid <- links do
          send pid, :foo
        end
      end
    end
    
    Parent.main
    :timer.sleep(1000)
    

    输出:

    Message received by 2: :foo
    Message received by 1: :foo
    Message received by 3: :foo
    

    我认为不可能直接获取进程的子进程列表:http://erlang.org/pipermail/erlang-questions/2013-April/073125.html。如果您从主管那里派生它们,有一些方法,但不是针对任意情况。

    【讨论】:

    • 这种方法的问题是链接是双向的。因此,如果您在主管下启动 Child,那么主管,即父母,也将在列表中并接收消息。最好存储您要与之交谈的 PID 的名称,或将它们置于主管之下并使用主管 API。
    • 这两个回答都非常有帮助。我也不知道主管——只是一个初学者!
    【解决方案2】:

    你看过 PubSub 吗?唯一的限制是您的所有进程都将被命名为相同的https://hexdocs.pm/elixir/master/Registry.html#module-using-as-a-pubsub

    {:ok, _} = Registry.start_link(:duplicate, Registry.PubSubTest)
    
    # process 1
    {:ok, _} = Registry.register(Registry.PubSubTest, "room_1", [])
    
    # process 2
    {:ok, _} = Registry.regiser(Registry.PubSubTest, "room_1", [])
    
    Registry.dispatch(Registry.PubSubTest, "room_1", fn entries ->
     for {pid, _} <- entries, do: send(pid, {:broadcast, "world"})
    end)
    #=> :ok
    

    【讨论】:

      猜你喜欢
      • 2015-01-29
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      • 2013-01-18
      • 1970-01-01
      • 2016-05-11
      • 2011-08-31
      • 2012-10-14
      相关资源
      最近更新 更多