ets:select相关api的介绍
- ets:select/2
- 对 ETS 表里的数据进行匹配比对
- select(Tab, MatchSpec) -> [Match]
- 使用一个匹配描述从表 Tab 里匹配对象。此函数调用比 ets:match/2 和 ets:match_object/2 更常用。以下是一些最简单形式的匹配描述:
MatchSpec = [MatchFunction]
MatchFunction = {MatchHead, [Guard], [Result]}
MatchHead = "Pattern as in ets:match"
Guard = {"Guardtest name", ...}
Result = "Term construct"
这意味着匹配描述总是含有一个以上元组元素的列表(含有三个参数的元组元素),元组的第一个元素应是 ets:match/2 的文档中所描述的模式,第二个元素应是含 0 个或多个断言测试的列表,第三个元素应是包含关于实际返回值的描述的列表,通常是一个对返回值全描述的列表,即返回匹配对象的所有项目。返回值的结构使用 MatchHead 所绑定的 “match variables”,或者使用特殊的匹配值’$ _'(整个匹配对象)和 ‘$$’(包含所有匹配值的列表)。
请看下列命令展示
1>Tab = ets:new(test_ets_new, [private]).
#Ref<0.3812907546.3525181460.80124>
2> ets:insert(Tab, [{a, 1}, {b, 2},{c,3},{d,4}]).
true
%%使用'$_'时返回的是匹配值数组
3> ets:select(Tab, [{{'$1', '$2'}, [], ['$$']}]).
[[d,4],[c,3],[b,2],[a,1]]
%%使用'$_'时返回的是对象数组
4> ets:select(Tab, [{{'$1', '$2'}, [], ['$_']}]).
[{d,4},{c,3},{b,2},{a,1}]
5> ets:select(Tab, [{{'$1', '$2'}, [], ['$1']}]).
[d,c,b,a]
6> ets:select(Tab, [{{'$1', '$2'}, [], ['$2']}]).
[4,3,2,1]
%%从这里开始,无论你在第三个位置写几个变量,都会以最后一个为准
7> ets:select(Tab, [{{'$1', '$2'}, [], ['$1','$2']}]).
[4,3,2,1]
8> ets:select(Tab, [{{'$1', '$2'}, [], ['$2','$2']}]).
[4,3,2,1]
9> ets:select(Tab, [{{'$1', '$2'}, [], ['$2','$1']}]).
[d,c,b,a]
10> ets:select(Tab, [{{'$1', '$2'}, [], ['$1','$1']}]).
[d,c,b,a]
11>
那如果是三元组呢
13> Tab3 = ets:new(test_ets_new3, [private]).
#Ref<0.3812907546.3525181460.80191>
14> ets:insert(Tab2, [{a, 1,A}, {b, 2,B},{c,3,C}]).
* 1: variable 'Tab2' is unbound
15> ets:insert(Tab3, [{a, 1,A}, {b, 2,B},{c,3,C}]).
* 1: variable 'A' is unbound
16> ets:insert(Tab3, [{a, 1,a1}, {b, 2,b1},{c,3,c1}]).
true
17> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$$']}]).
[[c,3,c1],[b,2,b1],[a,1,a1]]
18> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$_']}]).
[{c,3,c1},{b,2,b1},{a,1,a1}]
19> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$1']}]).
[c,b,a]
20> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$3']}]).
[c1,b1,a1]
21> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$2']}]).
[3,2,1]
22> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$2','$3']}]).
[c1,b1,a1]
23> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$2','$3','$1']}]).
[c,b,a]
24> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$2','$3','$2']}]).
[3,2,1]
25>
结果和二元组并无区别
ets:select/3和ets:select/1与match相关api类似,这里就不再赘述
- ets:select_delete/2
- 根据匹配模式删除表里的对象数据
- select_delete(Tab, MatchSpec) -> NumDeleted
使用一个匹配规范 MatchSpec 来匹配表 Tab 里的对象数据。如果对一条对象数据使用匹配规范时返回 true,并且该条对象数据会从表里移除。对于任何被匹配规范(match_spec)所匹配到的对象数据会被作为返回值而保留下来。该函数比 ets:match_delete/2 还更通用(ets:match_delete/2 的代码实现里还调用到 ets:select_delete/2 方法)。
函数最后会返回一个实际在表里被删除的对象的数量值。
5> ets:insert(Tab3, [{a,1,a1},{b,2,b2},{c,3,c3},{d,4,d4},{e,5,e5},{f,6,f6},{g,7,g7},{h,8,h8},{i,9,i9},{j,10,j10}]).
true
6> ets:select_delete(Tab3, [{{a, '_', '$1'}, [], [true]}]).
%% 返回匹配后删除对象的数量
1
7> ets:select(Tab3, [{{'$1', '$2','$3'}, [], ['$$']}]).
[[j,10,j10],
[i,9,i9],
[h,8,h8],
[g,7,g7],
[f,6,f6],
[e,5,e5],
[d,4,d4],
[c,3,c3],
[b,2,b2]]
8>
- ets:safe_fixtable/2
- 锁定一定 ETS 表使其可以安全遍历
- safe_fixtable(Tab, Fix) -> true
锁定一个类型是 set,bag 或 duplicate_bag 的表,使其可以安全遍历表里的数据
在一个进程里调用 ets:safe_fixtable(Tab, true) 可以锁定一个表,直到在进程里调用 ets:safe_fixtable(Tab, false) 才会解锁,或进程崩溃。
如果同时有几个进程锁定一个表,那么表会一直保持锁定状态,直到所有进程都释放它(或崩溃)。有一个引用计数器记录着每个进程的操作,有 N 个持续的锁定操作必须有 N 个释放操作,表才会真正被释放。
当一个表被锁定,一序列的 ets:first/1 和 ets:next/2 的调用都会保证成功执行,并且表里的每一个对象数据只返回一次,即使在遍历的过程中,对象数据被删除或插入。在遍历过程中插入到表里的新数据可能由 ets:next/2 返回(这取决有键的内部顺序)。
一个被锁定的表是不会有被删除的对象数据从表里被实际删除,直到它被释放。如果一个进程锁定一个表,并不释放它,那些已删除的对象数据所占用的内存将永远不会得到释放。对表操作的性能也会显著降低。
可以使用 ets:info/2 来查看有哪些进程锁定了表。有很多进程锁定表的系统需要一个监控来给那些锁定表很长时间的进程发送警告消息。
对于 ordered_set 类型的表,ets:safe_fixtable/2 是没必要的,因为 ets:first/1 和 ets:next/2 将总会调用成功。