在 GenServer.start_link/3
中,我可以像这样使用原子名称本地注册一个进程:
defmodule Worker do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, nil, name: :worker)
end
end
然后我可以启动一个supervisor来监督这个进程:
defmodule Boss do
use Supervisor
def init(_) do
children = [worker(Worker, [])]
supervise(children, strategy: :one_for_one)
end
end
现在我想让监管者监督3个“工人”进程,因此我需要为这些3个进程赋予唯一的名称,这样当监管者重新启动该进程时,它将始终使用相同的符号名称。
我可以简单地使用字符串插值来创建唯一的“工人”进程名称,例如:
defmodule Worker do
use GenServer
def start_link(id) do
GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
end
end
然后监督这样的3个进程:
defmodule Boss do
use Supervisor
def init(_) do
children = for id <- 1..3 do
worker(Worker, [id], id: id)
end
supervise(children, strategy: :one_for_one)
end
end
它像预期的那样工作。
在GenServer文档的“名称注册”部分下,它说你也可以使用{:via,module,term}
来注册名称。
{:via,module,term}
- 使用给定的机制和名称注册GenServer。:via
选项需要一个导出register_name /2
、unregister_name /1
、whereis_name /1
和send /2
的模块。一个这样的例子是:global
模块,它使用这些函数为Elixir节点网络中全局可用的进程的名称列表和关联的PID保留这些函数。Elixir还附带了一个本地的、去中心化的、可扩展的Registry注册表,用于动态生成并存储名称。
然而,要使用:via
选项,您必须实现一个导出register_name /2
、unregister_name /1
、whereis_name /1
和send /2
的模块,这似乎比上面显示的简单使用字符串插值技术困难得多。
所以我的问题是:
- 使用
{:via,module,term}
注册名称的好处是什么,而不仅仅是使用字符串插值? - 是否有使用
:via
选项注册名称的实用示例?