【问题标题】:Erlang LRU CacheErlang LRU Cache
【发布时间】:2016-07-28 18:33:36
【问题描述】:

如何用 Erlang 实现 LRU Cache?

LRU Cache Wiki

星号最高的 Github 项目是 fogfish/cache,但分段表不太适合我的数据。

barrel-db/erlang-lru 正在使用列表。经过测试,如果数据太多会很慢。

我猜问题出在这里。

move_front(List, Key) -> [Key | lists:delete(Key, List)].

对于 Java,更好的实现是使用 hashmaplinkedlist like this

我尝试做一个链表,然后意识到 链表对于 Erlang 来说不是个好主意like this thread

问题是如何用 Erlang 做 LRU 缓存?

【问题讨论】:

  • 我认为 Erlang 的级别太高了,不适合做低级缓存,目前,Erlang 在核心中有一些类似的特性(比如 ETS erlang.org/doc/man/ets.html),所以,你在使用外部之前测试了其中的一些特性吗?项目?
  • @MathieuK。谢谢你的cmets。是的,我试过了。关键问题是LRU。我尝试使用表来保存 access_time,但是对于每次读取/更新,我都需要更新(删除然后插入)表。我想知道这是否可以用更好的方法来完成?
  • 我对你的问题没有一个答案。如果你想在 Erlang 中实现高性能的 LRU 缓存,我想最好的方法之一是使用与 portsNIF 互连的外部代码。 C 编程不是我最喜欢的领域,但是,如果你想要一些为 Erlang 实现 C 代码的示例,你可以查看beam source code

标签: caching erlang lru


【解决方案1】:

THE CACHE 的第一个实现基于具有两个索引的 ETS。一个ets表是保持TTL -> Key关系,另一个ets表是Key -> Object。您可以在

处查看实现

https://github.com/fogfish/cache/commit/8cc50bffb4178ad9ad716703507c3290e1f94821

两个索引的维护效率不高,因此分段缓存优于原始实现。我不建议使用 Erlang 数据结构实现每个对象的 TTL,除非您可以在参与者中对数据进行建模并接受开销。有一个实现来解决它。它使用每个对象的进程概念:

https://github.com/fogfish/pts

否则需要实现NIF

【讨论】:

    【解决方案2】:

    我已经使用伪时间方法实现了 LRU 缓存(完整实现可在此处获得 https://github.com/poroh/erl_lru

    我有两个数据结构:

    1. 用于查找的无序映射:#{key() => {order(), value()}}
    2. 物品订购的有序地图:gb_tree(order(), key())

    order() 是伪时间:

    • 每次添加新元素或更新任何元素时都会递增
    • 每个属于 LRU 的元素都有自己的更新时间

    操作:

    由于使用gb_tree,所有操作都具有 O(log(N)) 复杂度。

    添加元素(键、值):

    • 增量时间(结果为 T)
    • 将 Key => {T, Value} 放入无序映射
    • 将 {T, Key} 放到有序映射中
    • 检查溢出

    更新元素(键):

    • 在无序映射中查找元素 Key => {T0, Value}
    • 增量时间(结果为 T)
    • 从无序映射中移除元素键
    • 从有序映射中移除元素 T0
    • 如上添加元素(键、值)

    检查溢出:

    • 如果缓存中的元素数量超过可能的最大值
      • 在有序映射 (T, Key) 中取最小 (gb_tree:take_smallest) 元素
      • 从有序映射中移除元素 T
      • 从无序中移除元素键

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 2017-01-25
      • 2012-09-30
      相关资源
      最近更新 更多