ets:foldl/3的文档说:
如果
Function
将对象插入表中,或者另一个进程将对象插入表中,则这些对象可能(取决于键顺序)包含在遍历中。
但是如果Function
从表中删除对象会发生什么?在这种情况下,是否可以保证所有剩余的对象都将包含在遍历中?
ets:foldl/3的文档说:
如果
Function
将对象插入表中,或者另一个进程将对象插入表中,则这些对象可能(取决于键顺序)包含在遍历中。
但是如果Function
从表中删除对象会发生什么?在这种情况下,是否可以保证所有剩余的对象都将包含在遍历中?
根据 ets.erl 的来源,如果一个进程正在迭代表并且在此期间它会删除记录,如果这些记录到目前为止尚未处理,则不会处理这些记录。
foldl(F, Accu, T) ->
ets:safe_fixtable(T, true),
First = ets:first(T),
try
do_foldl(F, Accu, First, T)
after
ets:safe_fixtable(T, false)
end.
辅助函数是
do_foldl(F, Accu0, Key, T) ->
case Key of
'$end_of_table' ->
Accu0;
_ ->
do_foldl(F,
lists:foldl(F, Accu0, ets:lookup(T, Key)),
ets:next(T, Key), T)
end.
首先 foldl 固定桌子。当一个进程修复一个表时,它将被记录到一个 {Time, Pid} 列表中。在固定表中,ets:first 和 ets:next 保证成功,每个对象只会返回一次。在有序表的情况下,ets:next 可以返回一个对象不再存在的键。但这不是问题,因为 ets:lookup 会返回一个空列表,以防记录不在表中。lists:foldl 在这种情况下不会失败。
所以答案是肯定的,其他记录会被ets:foldl处理。
如果您有多个进程同时操作表,则 safe_fixtable 将保护表免受并发操作。safe_fixtable/2 的文档说:
进程通过调用 safe_fixtable(Tab, true) 来修复表。该表保持固定,直到进程通过调用 safe_fixtable(Tab, false) 释放它,或者直到进程终止。
注意文档在这里所说的内容:
请注意,在固定表被释放之前,实际上不会从固定表中删除已删除的对象。如果一个进程修复了一个表但从未释放它,则被删除对象使用的内存将永远不会被释放。对表的操作性能也会显着下降。
因此,修复表格以进行遍历是有代价的。不要在 foldl 函数中做太多的操作,它也不应该花费太长时间。