【问题标题】:What are the differences between ETS, persistent_term and process dictionaries?ETS、persistent_term 和流程字典有什么区别?
【发布时间】:2021-04-20 10:33:20
【问题描述】:

我知道在 Erlang 中有(至少)三种方式来获得可变状态:

  • ETS 表格
  • persistent_term
  • 进程字典

它们的基本用法和我很像:

% ETS
1> ets:new(table1, [named_table]).
2> ets:insert(table1, {thing}).
3> ets:lookup(table1, thing).
[{thing}]

% persistent_term
1> persistent_term:put(table2, thing).
2> persistent_term:get(table2).
thing

% Process dictionary
1> put(table3, thing).
2> get(table3).       
thing

使用一个比另一个有什么区别和优点/缺点?

我发现 ETS 的行为更像一张地图,但它与将地图保存在 persistent_terms 或流程字典中有何不同?

【问题讨论】:

    标签: data-structures erlang ets


    【解决方案1】:

    @José 回答的一些免费信息:

    process_dictionary 是本地的,它随进程而死,无法从外部进程访问

    persistent_element 是全局的,它只与节点一起消亡。它可以被任何进程访问,不受控制。

    ETS 由一个进程拥有,它可以由不同的进程共享,它随所有者而死,所有权可以让给另一个进程,它提供一些访问控制(公共、私有、受保护)和不同的组织类型和访问。

    shell 中的一个简短会话显示(大部分)这些差异。

    12> persistent_term:put(global,value1).
    ok
    13> put(local,value2). % with process_dictionary, put returns the previous value associated to the key
    undefined
    14> ets:new(my_ets,[named_table,public]). % create a public table
    my_ets
    15> ets:insert(my_ets,{shared,value3,other_values}).
    true
    16> persistent_term:get(global).  % check that everything is stored                  
    value1
    17> get(local).                 
    value2
    18> ets:lookup(my_ets,shared).
    [{shared,value3,other_values}]
    19> ets:lookup_element(my_ets,shared,2). % a small example of ETS extended capabilities
    value3
    20> F1 = fun(From) -> From ! persistent_term:get(global) end. % prepare the same functions to be executed from external process
    #Fun<erl_eval.44.97283095>
    21> 
    21> F2 = fun(From) -> From ! get(local) end.                  
    #Fun<erl_eval.44.97283095>
    22> F3 = fun(From) -> From ! ets:lookup(my_ets,shared) end.
    #Fun<erl_eval.44.97283095>
    23> Me = self().
    <0.19320.1>
    24> spawn(fun() -> F1(Me) end).
    <0.12906.2>
    25> flush(). % persistent_term are global
    Shell got value1
    ok
    26> spawn(fun() -> F2(Me) end).
    <0.13701.2>
    27> flush(). % prrocess_dictionary is local                  
    Shell got undefined
    ok
    28> spawn(fun() -> F3(Me) end).
    <0.13968.2>
    29> flush().  % ETS can be shared                 
    Shell got [{shared,value3,other_values}]
    ok
    30> 1/0. % create an exception so the shell dies and is restarted by its supervisor
    ** exception error: an error occurred when evaluating an arithmetic expression
         in operator  '/'/2
            called as 1 / 0
    31> Me = self().  % the shell's Pid changed             
    ** exception error: no match of right hand side value <0.14499.2>
    32> persistent_term:get(global).    % persistent are still there                          
    value1
    33> get(local).  % Oooops! the process dictionary is still there too. Warning, this is a side effect of the shell implementation                                             
    value2
    34> ets:lookup(my_ets,shared).  % my_ets does not exist anymore                      
    ** exception error: bad argument
         in function  ets:lookup/2
            called as ets:lookup(my_ets,shared)
    35> 
    

    【讨论】:

      【解决方案2】:

      persistent_termets 公开了类似的 API,但它们不同,我将引用 manual

      持久术语是一项高级功能,不是 ETS 表的一般替代品。

      不同之处在于术语存储在哪里以及更新时会发生什么,ETS 术语在读取时被复制到进程堆,其中persistent_term 术语仅被引用。这导致当 persistent_term 中的项目更新时,所有拥有该术语副本(引用)的进程都需要将其实际复制到它们的堆中才能继续使用它。

      对于庞大的条款,引用它们而不是复制它们可以节省大量时间,但更新的代价是严厉的。

      另外,persistent_term 只是一个映射,而 ETS 可能是一个集合、有序集合、包或重复包,ETS 也提供选择和匹配语义。

      persistent_term 被用作 ETS 用于非常具体的用例的优化替代品。

      关于进程字典,它是进程内部的本地#{},始终可用。 ETS 和persistent_term 可用于每个进程,每个进程的本地进程字典不同。使用进程字典时要非常小心,因为它会影响可读性。

      【讨论】:

        猜你喜欢
        • 2012-03-14
        • 2011-02-22
        • 2015-10-24
        • 2012-04-03
        • 2014-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-10
        相关资源
        最近更新 更多