在 Elixir 中获取兄弟进程

Getting a sibling process in Elixir

我有一个 Elixir/Erlang 进程树:

parent (Supervisor)
├── child1 (GenServer)
└── child2 (GenServer)

child1(数据库客户端)有child2需要使用的信息。将 Supervisor 进程的引用传递给 child2 以便 child2 始终具有对 child1 的有效引用的好方法是什么?我是否只需要重组我的应用程序,让 child2 由 child1 监督?

最简单的方法可能是在本地别名下注册 child1child2。您可以在启动 GenServer 时通过传递 name 选项来做到这一点:

defmodule Child1 do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end
end

在这种情况下,Child1 模块支持的进程将在本地注册为别名 Child1。然后,如果您想向它发送消息,您可以使用该别名而不是 PID.

defmodule Child1 do
  # ...

  def get_data do
    GenServer.call(__MODULE__, :get_data)
  end

  def handle_call(:get_data, _from, state) do
    {:reply, extract_data_from_state(state), state}
  end
end

如果您想要一个更复杂的解决方案,例如可以注册许多相同类型的不同进程,请查看 gproc library

我不使用 Elixir,但我使用 Erlang,我认为我的回答在这两种情况下都有效。

如果您的 child1 类型的进程是永久的,并且数量固定,那么最简单的解决方案是注册它们(game_server、event_server、...)

但是如果生命短暂,数量不固定,或者会存在很多同类进程(比如游戏中的玩家进程),我建议换个组织:

  • 顶级主管启动 2 个进程,一台服务器和一个主管。
  • 服务器至少会维护一个列表,其中包含所有活动的 "child1" 进程,这些进程具有允许访问它们的某些特征(玩家 ID ...)。一般它也会使用supervisor进程来启动,杀掉..."child1"个进程。
  • 主管是一个简单的工厂,它将使用 simple_one_for_one 策略创建和监督 "child1"。

    parent (Supervisor) ├── child2 (GenServer) └── Client_supervisor(Supervisor) ├── Client_server(registered GenServer) └── Client_factory(registered Supervisor) ├── Child1(GenServer) ├── Child1'(GenServer) └── ...