我需要在ets集中跟踪大量的进程,然后随机选择单个进程。所以我创建了这样的集合:
:ets.new(:pid_lookup, [:set, :protected, :named_table])
然后为了论证,让我们将self()
坚持1000次:
Enum.map 1..1000, fn x -> :ets.insert(:pid_lookup, {x, self()}) end
现在我需要随机选择一个。我知道我可以使用:ets.lookup(:pid_lookup, :rand.uniform(1000))
随机选择一个,但是如果我事先不知道集合的大小(在上述情况下为1000)怎么办?
如何找出一个ets集的大小?和/或有没有更好的方法从ets数据结构中选择随机pid?
答案 0 :(得分:1)
tab = :ets.new(:tab, [])
Enum.each(1..1000, & :ets.insert(tab, {&1, :value}))
size = :ets.info(tab, :size)
# size = 1000
value_picked_randomly = :ets.lookup(tab, Enum.random(1..1000))
:ets.info(tab, :size)
返回表的大小;这是在给定表上插入的许多记录。
first = :ets.first(tab)
:ets.lookup(tab, first)
func = fn key->
if function_that_may_return_true() do
key = case :ets.next(tab, key) do
:'$end_of_table' -> throw :reached_end_of_table
key -> func.(key)
end
else
:ets.lookup(tab, key)
end
end
func.()
func
将遍历ets表并返回一个随机值。
这将很耗时,因此对于具有大量记录的表而言,它并不是理想的解决方案。
答案 1 :(得分:-1)
根据我的评论,这是XY Problem。
您真正需要的是跟踪更改列表并随机选择其元素之一。一般而言,ETS
,尤其是:ets.set
绝不打算查询大小。它们有不同的用途。
在您的监督树中生成Agent
,保留已启动服务器的PID列表,并使用Kernel.length/1
查询其大小,如果列表不是<,则甚至使用Enum.random/1
em>真正巨大(后者遍历整个枚举以获取随机元素。)