1. ETS和DETS簡介:
ETS(Erlang Term Storage )和DETS(Dist ETS)是Erlang用於高效存儲大量Erlang數據條目的系統模塊。
ETS與DETS的比較:
相同:ETS和DETS都提供大型的“鍵-值”搜索表。
不同:ETS駐留在內存,DETS駐留在硬盤。ETS存儲是臨時的,DETS中的數據存儲是持久的。
ETS非常高效,在ETS中,無論你存儲多少數據,查詢速度都與之無關(特定情況成對數關系),前提是擁有足夠大的內存。DETS相對效率要低很多,但比ETS更加節省內存。
ETS表和DETS表可以被多個進程共享,可以通過這兩個模塊實現進程間高效的數據交換。
ETS不是由Erlang本身來實現的,而是由底層運行時系統來實現的。相比一般的Erlang對象,ETS有很多不同。如,ETS不會被垃圾回收。
ETS或DETS,本質就是一系列Erlang元組。
2. 表的基本操作:
1. 創建新表或打開一個已存在的表:ets:new() 或 dets:open_file()
2. 將一個或多個元組插入表:insert(TableName,X) 。 X是一個元組或元組的列表。
3. 在表中查找元組:lookup(TableName,Key)
返回匹配Key的元組列表
4. 釋放表:dets:close(TableId) 或ets:delete(TableId)
3. 表的類型:(4種)
set ordered set bag duplicate bag
類型為set的表,要求所有元組的鍵值各不相同;
ordered set表,按鍵值大小排序。
類型為bag的表,允許多個元組有相同的鍵值,但不允許有相同的元組。
類型為duplicate bag的表,允許有多個相同的元組。
4. ETS舉例:ets_test.erl
-module(ets_test).
-export([start/0]).
start() ->
lists:foreach(fun test_ets/1,
[set,ordered_set,bag,duplicate_bag]).
test_ets(Mode) ->
TableId = ets:new(test_ets,[public,named_table,Mode]),
ets:insert(TableId,{a,1}),
ets:insert(TableId,{b,2}),
ets:insert(TableId,{a,1}),
ets:insert(TableId,{a,3}),
%%因建立ets表時,使用了named_table模式,所以使用ets表時可直接使用ets表的Name
List = ets:tab2list(test_ets),
io:format("~-13w =>~p~n",[Mode,List]),
ets:delete(test_ets).
運行結果:
1> ets_test:start().
set =>[{b,2},{a,3}] 注:set每個鍵值只允許出現一次,所以{a,1}最終被{a,3}覆蓋。
ordered_set =>[{a,3},{b,2}]
bag =>[{b,2},{a,1},{a,3}]
duplicate_bag =>[{b,2},{a,1},{a,1},{a,3}]
5. ETS的效率考慮:
1. 在內部,ETS表是用散列來表示的(除了ordered set是用平衡二叉樹來表示的)
所以set有點浪費空間,ordered set有點浪費時間。set表插入數據所耗費時間是常量,而order set插入所耗時間與表的大小成對數關系。
bag比duplicate bag的使用代價要高,因為每次插入都要比較鍵值。
2. ETS表與正常的進程存儲空間分離,不會進行垃圾回收。
3. ETS表隸屬於創建他的進程,當這個進程死掉或者調用ets:delete,這個表就被刪掉。
4. 在進程之間發送大量二進制數據的消息,或者向ETS表中插入包含二進制數據的元組,代價都很低。
因此,盡可能地用二進制數據表示字符串或大塊的無類型數據,是一種高效的編程方式。
6. ETS表的創建:
ets:new(Name,[Option])
Name是表的名字,是一個原子atom。
OPtion是選項列表,取值如下:
set | ordered_set | bag | duplicate_bag
private | protected | public
named_table 表示可使用Name來操作表
{Keypos,K}
打開一個ETS表時不帶任何選項,則默認選項是[ets,proteced,{keypos,1}]