Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 什么';在GenServer.start_link/3中使用{:via,module,term}注册名称的好处是什么?_Elixir_Otp_Erlang Supervisor_Gen Server - Fatal编程技术网

Elixir 什么';在GenServer.start_link/3中使用{:via,module,term}注册名称的好处是什么?

Elixir 什么';在GenServer.start_link/3中使用{:via,module,term}注册名称的好处是什么?,elixir,otp,erlang-supervisor,gen-server,Elixir,Otp,Erlang Supervisor,Gen Server,在GenServer.start\u link/3中,我可以使用atom在本地注册一个名称,用于如下过程: defmodule Worker do use GenServer def start_link do GenServer.start_link(__MODULE__, nil, name: :worker) end end defmodule Worker do use GenServer def start_link(id) do GenSer

GenServer.start\u link/3
中,我可以使用atom在本地注册一个名称,用于如下过程:

defmodule Worker do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, nil, name: :worker)
  end
end
defmodule Worker do
  use GenServer

  def start_link(id) do
    GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
  end
end
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
然后我可以启动一个主管来监督这个过程:

defmodule Boss do
  use Supervisor

  def init(_) do
    children = [worker(Worker, [])]
    supervise(children, strategy: :one_for_one)
  end
end
现在我想让主管管理3个
工作进程
进程,因此我需要为这3个进程指定唯一的名称,以便主管重新启动进程时始终使用相同的符号名称

我可以简单地对唯一的
Worker
进程名使用字符串插值,如下所示:

defmodule Worker do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, nil, name: :worker)
  end
end
defmodule Worker do
  use GenServer

  def start_link(id) do
    GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
  end
end
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
然后监督以下3个过程:

defmodule Worker do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, nil, name: :worker)
  end
end
defmodule Worker do
  use GenServer

  def start_link(id) do
    GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
  end
end
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
defmodule Boss do
使用主管
def init(u)do

children=for id使用
:通过
元组可以很好地封装别名处理,并为您提供一个可以发现进程的固定点。此外,
:via
元组可以是任意复杂的,例如像
{:my_worker,1}
这样的元组通常比处理字符串操作更好


(请注意,我正在学习长生不老药,所以不要相信我的话。此外,对于
:通过
元组,可能会有更有力/更好的论据。)

tl;dr-
:via
允许您使用非标准流程注册库。它们必须符合接口(很像在Java中实现接口),并且可能提供额外的功能

主要示例是当您希望使用非标准名称注册库时。以美国为例。它遵循接口要求使用
:via
,因此对应用程序代码的入侵要求最小。此外,与标准名称注册系统相比,它还提供了一些优势:

  • 使用任何术语作为流程别名
  • 在多个别名下注册进程
  • 非唯一属性可以由多个进程同时注册;和匹配规范接口,以便在字典上进行高效查询
  • 等待注册,让我们等待进程注册自己
  • 以原子方式将注册的名称和属性传递给另一个进程
  • 计数器和聚合计数器,它们自动维护具有给定名称的所有计数器的总数
  • 全局注册表,所有上述功能均应用于节点网络

  • Elixir的
    注册表
    模块是另一个需要via元组的示例。

    一个场景是,当您想动态地为员工分配姓名时(可能他们由
    动态监督人
    简单的一对一监督人
    监督人监督,并随时间动态生成)

    因为原子从来都不是垃圾收集的,所以你不能用它们作为那些工作者的名字,否则你将不得不处理内存泄漏问题

    出于某种原因,在
    :global
    模块上注册名称让我感到不舒服,因为全局状态通常被认为是邪恶的,特别是在高度并发的环境中(这就是为什么选择Erlang/Elixir)

    因此,在本例中,最好在“名称空间”中注册名称。在这种情况下,
    {:via,module,term}
    变体会发光。
    模块
    用作名称空间,
    术语
    可以是任何内容(通常是字符串,因为它易于理解,并且是垃圾收集的)


    顺便说一句,如果您不想自己实现注册表,那么已经有了一个用于此目的的模块。您只需要给注册表进程一个名称并对其进行监督。

    我也有同样的问题。我可以想出两个原因来解释为什么您希望使用
    注册表
    模块而不是生成动态名称,例如
    :“worker:{id}”

    • 原子不是垃圾收集的
    • 根据:“注册表中的每个条目都与注册该项的进程相关联。如果该进程崩溃,与该进程关联的项将自动删除。”
    因此,注册表似乎链接到其中的进程,如果这些进程失败,注册表将删除这些条目:

    iex(6)> {:ok, _} = Registry.start_link(keys: :unique, name: Registry.ViaTest2)
    {:ok, #PID<0.445.0>}
    iex(7)> name = {:via, Registry, {Registry.ViaTest2, "agent"}}
    {:via, Registry, {Registry.ViaTest2, "agent"}}
    iex(8)> {:ok, agent} = Agent.start(fn -> 0 end, name: name)
    {:ok, #PID<0.449.0>}
    iex(9)> Registry.lookup(Registry.ViaTest2, "agent")
    [{#PID<0.449.0>, nil}]
    iex(10)> Process.alive?(agent)
    true
    iex(11)> Process.exit(agent, :kill)
    true
    iex(12)> Process.alive?(agent)
    false
    iex(13)> Registry.lookup(Registry.ViaTest2, "agent")
    []
    
    iex(6)>{:ok,{}=Registry.start\u链接(key::unique,name:Registry.ViaTest2)
    {:好的,#PID}
    iex(7)>name={:via,Registry,{Registry.ViaTest2,“agent”}
    {:via,注册表,{Registry.ViaTest2,“代理”}
    iex(8)>{:ok,agent}=agent.start(fn->0 end,name:name)
    {:好的,#PID}
    iex(9)>Registry.lookup(Registry.ViaTest2,“代理”)
    [{PID,nil}]
    iex(10)>进程。活动?(代理)
    真的
    iex(11)>进程退出(代理:终止)
    真的
    iex(12)>进程。活动?(代理)
    假的
    iex(13)>Registry.lookup(Registry.ViaTest2,“代理”)
    []