【问题标题】:Why it would be better keeping track of #Reference than #PID when implementing a GenServer?为什么在实现 GenServer 时跟踪#Reference 比跟踪#PID 更好?
【发布时间】:2016-09-21 19:19:30
【问题描述】:

Elixir 的 Mix and OTP Guide Chapter GenServer 解释了如何使用 GenServer 实现注册服务器持有代理。

每个代理的 PID 都保存在一个映射中,其中键是客户端给出的代理名称,值是代理的 PID。

为了避免保留对死代理的引用,该指南建议使用 Process.monitor/1 监视新创建的代理,并通过添加一个名为 refs 的新映射稍微修改状态,其中包含引用(由 Process.monitor/1 返回的值)作为键和代理的名称作为值。它还展示了如何使用handle_info/2 处理监控消息以更新refs

Process.monitor/1 接收一个 PID(例如#PID<0.66.0>)作为参数并返回一个引用(例如#Reference<0.0.0.551>)。 handle_info/2 捕获的 :DOWN 消息提供了 PID 和引用。

因为我们一直都知道这两个值:使用引用作为键比在 refs 中使用 PID 有什么好处?

【问题讨论】:

    标签: elixir gen-server


    【解决方案1】:

    这是一个一致性问题。虽然您只监控进程,但没有区别。但底层:erlang.monitor/2 不能监控 进程:有端口等,基本上没有PID

    来自文档:

    Object

    触发事件的受监控实体。监视本地进程或端口时,Object 将等于被监视的 pid()port()。当按名称监视进程或端口时,Object 将具有格式 {RegisteredName, Node},其中 RegisteredName 是与 monitor/2 调用一起使用的名称,Node 是本地或远程节点名称(对于按名称监视的端口, Node 始终是本地节点名称)。

    总结:Reference 是一个实体,被监控。它可能是一个进程,一个端口,等等。虽然您不想demonitor/1 关闭监视端口的整个过程,但您应该使用引用。

    【讨论】:

      【解决方案2】:

      如果您只是有一个小项目并且想监控某些进程,只需记住 PID 就可以了。但我建议使用参考,因为项目增长很快,您可能不仅要监控流程。 Elixir 在:erlang.monitor/2 下使用,它还可以让您在Erlang 单调时间和Erlang 系统时间之间监控portstime_offset。这可以在Docs here 中找到。参考更通用,是一般使用参考的更好做法。

      这里是我想说的一个小例子:

      iex(1)> :erlang.monitor(:time_offset, :clock_service)
      #Reference<0.0.3.100>
      
      iex(2)> :erlang.monitor(:process ,self())
      #Reference<0.0.3.113>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 2020-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多