在每条记录上使用 ets:foldl 作为穷人的 forEach
简短版本:在迭代时使用 ets:foldl
删除每条 ETS 记录是否安全?
假设 ETS 表正在累积信息,现在需要进行处理这一切。从表中读取记录,以某种方式使用,然后删除。 (另外,假设该表是私有
,因此没有并发问题。)
在另一种语言中,具有类似的数据结构,您可以使用 for...each 循环,处理每条记录,然后将其删除来自哈希/字典/地图/任何内容。但是,ets
模块没有 foreach
,例如 lists
。
但这可能有效:
1> ets:new(ex, [named_table]).
ex
2> ets:insert(ex, {alice, "high"}).
true
3> ets:insert(ex, {bob, "medium"}).
true
4> ets:insert(ex, {charlie, "low"}).
true
5> ets:foldl(fun({Name, Adjective}, DontCare) ->
io:format("~p has a ~p opinion of you~n", [Name, Adjective]),
ets:delete(ex, Name),
DontCare
end, notused, ex).
bob has a "medium" opinion of you
alice has a "high" opinion of you
charlie has a "low" opinion of you
notused
6> ets:info(ex).
[...
{size,0},
...]
7> ets:lookup(ex, bob).
[]
这是首选方法吗?它至少是正确且无错误的吗?
我普遍担心在处理数据结构时修改数据结构,但是 ets:foldl 文档 意味着 ETS 非常乐意让您修改 foldl
内的记录。因为我基本上是在把桌子擦干净,所以我想确定一下。
我正在使用 Erlang R14B 和 set
表,但是我想知道任何 Erlang 版本或任何类型的表是否有任何警告。谢谢!
Short version: is it safe to use ets:foldl
to delete every ETS record as one is iterating through them?
Suppose an ETS table is accumulating information and now it's time to process it all. A record is read from the table, used in some way, then deleted. (Also, assume the table is private
, so no concurrency issues.)
In another language, with a similar data structure, you might use a for...each loop, processing every record and then deleting it from the hash/dict/map/whatever. However, the ets
module does not have foreach
as e.g. lists
does.
But this might work:
1> ets:new(ex, [named_table]).
ex
2> ets:insert(ex, {alice, "high"}).
true
3> ets:insert(ex, {bob, "medium"}).
true
4> ets:insert(ex, {charlie, "low"}).
true
5> ets:foldl(fun({Name, Adjective}, DontCare) ->
io:format("~p has a ~p opinion of you~n", [Name, Adjective]),
ets:delete(ex, Name),
DontCare
end, notused, ex).
bob has a "medium" opinion of you
alice has a "high" opinion of you
charlie has a "low" opinion of you
notused
6> ets:info(ex).
[...
{size,0},
...]
7> ets:lookup(ex, bob).
[]
Is this the preferred approach? Is it at least correct and bug-free?
I have a general concern about modifying a data structure while processing it, however the ets:foldl documentation implies that ETS is pretty comfortable with you modifying records inside foldl
. Since I am essentially wiping the table clean, I want to be sure.
I am using Erlang R14B with a set
table however I'd like to know if there are any caveats with any Erlang version, or any type of table as well. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的方法是安全的。它安全的原因是
ets:foldl/3
内部使用ets:first/1、ets:next/2
和ets:safe_fixtable/2
代码>.这些有你想要的保证,即你可以杀死元素并仍然获得完整的遍历。请参阅 erl -man ets 的 CONCURRENCY 部分。为了从表中删除所有元素,有一个更简单的单行:
虽然它不起作用,但如果您想对每一行进行 IO 格式化,在这种情况下,您可以使用
foldl
可能更容易。Your approach is safe. The reason it is safe is that
ets:foldl/3
internally useets:first/1, ets:next/2
andets:safe_fixtable/2
. These have the guarantee you want, namely that you can kill elements and still get the full traverse. See the CONCURRENCY section oferl -man ets
.For your removal of all elements from the table, there is a simpler one-liner however:
although it doesn't work should you want to do the IO-formatting for each row in which case your approach with
foldl
is probably easier.对于这样的情况,我们将在两个表之间交替,或者在每次开始处理时创建一个新表。当我们想要开始一个处理周期时,我们切换写入器以开始使用备用表或新表,然后我们进行处理并清除或删除旧表。
我们这样做是因为否则我们可能会错过对元组的并发更新。当我们使用这种技术时,我们正在使用高频并发计数器。
For cases like this we will alternate between two tables or just create a new table every time we start processing. When we want to start a processing cycle we switch the writers to start using the alternate or new table, then we do our processing and clear or delete the old table.
We do this because there might otherwise be concurrent updates to a tuple that we might miss. We're working with high frequency concurrent counters when we use this technique.