【问题标题】:Storing state in Elixir在 Elixir 中存储状态
【发布时间】:2018-05-21 03:51:52
【问题描述】:

最近我解决了一个涉及更新大量键值的问题。

当然,我考虑使用Map,像Map.put/3 这样的操作。

然而,鉴于 Elixir 中数据结构的不可变特性,这似乎还不够:

iex> m = Map.put(%{}, :a, 1)
%{a: 1}
iex> Map.put(m, :b, 2)
%{a: 1, b: 2}
iex> m
%{a: 1}

然后我通过将Map 的状态保存在GenServer 中并使用handle_cast/3 调用更新它来解决问题。

一般来说,这是正确的方法,还是这里太过分了?

【问题讨论】:

    标签: dictionary elixir immutability gen-server mutability


    【解决方案1】:

    然后我通过将Map 的状态保存在GenServer [...] 一般来说,这是正确的方法,还是这里太过分了?

    这在很大程度上取决于您的目标。 存储状态有很多不同的方法。重新绑定变量,例如:

    m = Map.put(%{}, :a, 1)
    #⇒ %{a: 1}
    m = Map.put(m, :b, 2)
    #⇒ %{a: 1, b: 2}
    

    存储任何东西。它将局部变量m 绑定到 RHO,一旦控制流离开作用域,这个变量就会被垃圾回收。无论您是否需要在单个范围内使用上述地图,GenServer(和其他状态持有者)都是大材小用。


    OTOH,如果您需要长时间存储状态并在不同范围(例如,不同进程之间)之间共享它,GenServer 是实现此目的的最简单方法。在 Elixir 中,我们有 Agent 模块来减少 GenServer 的样板文件,它用作简单的内存存储,但我的建议是始终使用 GenServer:迟早 Agent 会变得太紧你的目的。

    另外,可以使用ets 模块来保持内存中的键值存储,在进程之间共享。

    dets 是一种存储状态进程重新启动之间的方式。

    最后,mnesia 是一种 OTP 原生方法,用于在重启和不同节点之间共享状态(在分布式环境中。)

    【讨论】:

      【解决方案2】:

      你的第一个方法是对的,你只是做错了。

      您应该在更新地图时重新绑定变量,如下所示:

      iex> m = Map.put(%{}, :a, 1)
      %{a: 1}
      iex> m = Map.put(m, :b, 2)
      %{a: 1, b: 2}
      iex> m
      %{a: 1, b: 2}
      

      但你必须明白,它不会改变变量,它会创建一个新映射并将其重新绑定到同一个变量。

      现在,这种方法是最简单的一种,您必须将此映射传递给使用它的每个函数。作为替代方案,您可以考虑使用Agent 模块。它是什么以及它的用途的所有信息都可以在其文档中找到。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-21
        相关资源
        最近更新 更多