0

ets:foldl/3的文档说:

如果Function将对象插入表中,或者另一个进程将对象插入表中,则这些对象可能(取决于键顺序)包含在遍历中。

但是如果Function从表中删除对象会发生什么?在这种情况下,是否可以保证所有剩余的对象都将包含在遍历中?

4

1 回答 1

2

根据 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 函数中做太多的操作,它也不应该花费太长时间。

于 2013-12-02T21:59:22.510 回答