sbs*_*sbs 11 elixir erlang-otp gen-server erlang-supervisor
在GenServer.start_link/3我可以使用原子在本地注册一个名称,用于这样的过程:
defmodule Worker do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, nil, name: :worker)
end
end
Run Code Online (Sandbox Code Playgroud)
然后我可以开始一个主管来监督这个过程:
defmodule Boss do
use Supervisor
def init(_) do
children = [worker(Worker, [])]
supervise(children, strategy: :one_for_one)
end
end
Run Code Online (Sandbox Code Playgroud)
现在我想让主管监督3个Worker进程,所以我需要为这3个进程提供唯一的名称,这样当supervisor重新启动进程时,它将始终使用相同的符号名称.
我可以简单地使用字符串插值作为唯一的Worker进程名称,如下所示:
defmodule Worker do
use GenServer
def start_link(id) do
GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
end
end
Run Code Online (Sandbox Code Playgroud)
然后监督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
Run Code Online (Sandbox Code Playgroud)
它像预期的那样工作.
在" 名称注册"部分的 GenServer文档中,它表示您也可以使用{:via, module, term}注册名称.
{:via,module,term} - GenServer注册了给定的机制和名称.:via选项需要一个导出register_name/2,unregister_name/1,whereis_name/1和send/2的模块.一个这样的例子是:全局模块,它使用这些函数来保存进程名称列表及其关联的pid,这些列表可以在Erlang节点网络中全局使用.
然而,为了使用:via选项,你必须执行,出口模块register_name/2,unregister_name/1,whereis_name/1和send/2,这似乎很繁琐比较简单地使用字符串插值技术,如上图所示.
所以我的问题是:
:via选项注册名称的实用示例?主要示例是当您要使用非标准名称注册库时。以gproc库为例。它遵循使用的接口要求:via,因此对您的应用程序代码的入侵最少。此外,与标准名称注册系统相比,它还具有一些优点:
Elixir的Registry模块是另一个需要via元组的示例。
tl; dr- :via是否允许您使用非标准的过程注册库。它们必须符合接口(非常类似于用Java实现接口),并且可能提供额外的功能。
使用:via元组可以让您很好地封装别名处理,并为您提供一个可以发现进程的固定点。此外,:via元组可以是任意复杂的,例如这样的元组{:my_worker, 1}通常比乱搞字符串操作更好。
(请注意,我正在学习 Elixir,所以不要相信我的话。此外,元:via组可能有更强/更好的论据。)