ETS、persistent_term 和过程字典之间有什么区别?
What are the differences between ETS, persistent_term and process dictionaries?
我知道(至少)有三种方法可以在 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
两者之间有何区别?pros/conspros/cons
我发现 ETS 的行为更像一张地图,但它与将地图保存在 persistent_term
或流程字典中有何不同?
persistent_term
和ets
暴露了类似的API,但它们是不同的,我会引用manual:
Persistent terms is an advanced feature and is not a general replacement for ETS tables.
不同之处在于术语存储在哪里以及更新时会发生什么,ETS 术语在读取时复制到进程堆,其中 persistent_term
术语仅被引用。这导致当 persistent_term
中的项目更新时,所有拥有该术语副本(引用)的进程都需要实际将其复制到它们的堆中才能继续使用它。
对于庞大的术语,引用它们而不是复制它们可以节省大量时间,但更新的代价是严厉的。
此外,persistent_term
只是一个映射,而ETS可以是集合、有序集合、包或重复包,ETS也提供select和匹配语义。
persistent_term
用作 ETS 所用的非常具体用例的优化替代品。
关于进程字典,它是进程内部的本地#{}
,始终可用。 ETS 和 persistent_term
可用于每个进程,每个进程的本地进程字典不同。使用进程字典时要非常小心,因为它会影响可读性。
@José 回答的一些补充信息:
process_dictionary是本地的,随进程消亡,无法被外部进程访问
persistent_element 是全局的,它只随节点消亡。它可以被任何进程访问,不受控制。
ETS由一个进程拥有,它可以被不同的进程共享,它与所有者同归于尽,所有权可以让给另一个进程,它提供了一些访问控制(public,private, protected) 和不同的组织类型和访问权限。
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>
我知道(至少)有三种方法可以在 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
两者之间有何区别?pros/conspros/cons
我发现 ETS 的行为更像一张地图,但它与将地图保存在 persistent_term
或流程字典中有何不同?
persistent_term
和ets
暴露了类似的API,但它们是不同的,我会引用manual:
Persistent terms is an advanced feature and is not a general replacement for ETS tables.
不同之处在于术语存储在哪里以及更新时会发生什么,ETS 术语在读取时复制到进程堆,其中 persistent_term
术语仅被引用。这导致当 persistent_term
中的项目更新时,所有拥有该术语副本(引用)的进程都需要实际将其复制到它们的堆中才能继续使用它。
对于庞大的术语,引用它们而不是复制它们可以节省大量时间,但更新的代价是严厉的。
此外,persistent_term
只是一个映射,而ETS可以是集合、有序集合、包或重复包,ETS也提供select和匹配语义。
persistent_term
用作 ETS 所用的非常具体用例的优化替代品。
关于进程字典,它是进程内部的本地#{}
,始终可用。 ETS 和 persistent_term
可用于每个进程,每个进程的本地进程字典不同。使用进程字典时要非常小心,因为它会影响可读性。
@José 回答的一些补充信息:
process_dictionary是本地的,随进程消亡,无法被外部进程访问
persistent_element 是全局的,它只随节点消亡。它可以被任何进程访问,不受控制。
ETS由一个进程拥有,它可以被不同的进程共享,它与所有者同归于尽,所有权可以让给另一个进程,它提供了一些访问控制(public,private, protected) 和不同的组织类型和访问权限。
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>