【问题标题】:Using an ets table for a gen_server state将 ets 表用于 gen_server 状态
【发布时间】:2011-05-15 07:39:47
【问题描述】:

我正在编写一个 gen_server,我想将 ets 表作为状态保存,然后在其他地方创建 ets 表。我应该如何将它添加到 gen_server 的状态中?

我想使用 ets 表而不是为它创建一个新字典,因为我想节省内存。

另外,如何遍历 ets 表?我想迭代或读取表中的每个值并检查值,然后我想根据值执行两个选项之一。

只是把ets表转成列表,遍历列表会不会更简单?

谢谢

【问题讨论】:

    标签: erlang gen-server


    【解决方案1】:

    一些建议:

    • 阅读 ETS 手册页:erl -man ets
    • ETS 表通过其名称(在named_table 选项的情况下)或通过其表ID 来标识。将该信息传递给 gen_server 并保持其状态:

      -record(state, { ..., tbl = none }).
      
      
      init([TableID]) ->
          ...,
          {ok, #state { tbl = TableID }}.
      

    ETS 可能不会节省那么多内存。稍后的 Erlang/OTP 版本会出现一个新标志,其中 ETS 表可以是compressed,因此它们的内容在存储之前被压缩,在读取时被解压缩(这会产生计算开销)。

    要遍历 ETS 表,您有多种选择。 ets:first/1 ets:next/2 就是这样一种接口。 ets:foldl/3 ets:foldr/3 另一个。 ets:match/3 为您提供了一个继续(光标)来行走。 ets:select 比匹配更笼统。

    把它变成一个列表会更容易吗?这取决于。 ETS 表的强大之处在于它们有一个选项{keypos, N},定义了存储元素的键。 ets:lookup(?TAB, Key) 非常快,因此您可以快速查找键。列表并非如此。但另一方面,如果您总是遍历所有列表,它可能是一个更简单的解决方案(只要您不在进程之间传递大列表)。

    也许应该避免将整个表变成一个列表并遍历它。您将在内存中生成列表,然后遍历它,这很昂贵。一次遍历一点会更好,这样实时内存量就会减少。

    【讨论】:

    • 谢谢。我想正确解决一些问题。在创建二进制位域之前,我们为 torrent 表示创建一个 ets 表。我想读取 ets 表并从所需的块中创建一个队列。对等处理程序将访问此队列以避免重复请求。一旦正确接收到块,该项目就会从队列中删除,并且位域或种子状态会更新。我想跟踪 GUI 的 torrent 状态以显示进度条等。我想知道是应该从 ets 表创建字典还是直接编辑表?
    • etorrent 使用两阶段过程。每个对等点单独读取 ETS 表并决定它想要什么。但是表是protected,所以所有实际分配都发生在第二阶段:调用管理块管理器,它序列化对表的访问,因此不会有两个进程意外抓取同一个块。它产生有效的并行性,同时仍然提供进步和安全性。
    • 好的,我们将从所需的块中创建一个队列。如果块不在内存中,它们是否不驻留在磁盘上,例如ets表。我想块管理器可以跟踪正在抓取的内容并阻止重复抓取,但是通过抓取或访问数据,是否会在发送整个二进制文件之前完成?
    • 既然您问:我将 16K 块二进制数据直接发送到磁盘上的正确位置,并且从不将它们保留在内存中。因此,我们可以尽快使用内核磁盘缓存层(它比我们做得更好)并且我们将内存保持在客户端中。存储在 ETS 表中的是我们在磁盘上拥有的和没有的。 piece 完成后,我们从磁盘读回整个片段,对其进行 SHA1 处理,然后验证/无效。如果我们快一点,磁盘缓存无论如何都会保存它,所以价格不高
    猜你喜欢
    • 2011-01-10
    • 2013-06-01
    • 2019-07-10
    • 2011-07-04
    • 2017-04-11
    • 2010-12-09
    • 1970-01-01
    • 2015-01-21
    • 2012-04-03
    相关资源
    最近更新 更多