【问题标题】:Why do we have clojure memoize function?为什么我们有 clojure memoize 功能?
【发布时间】:2017-10-07 15:27:19
【问题描述】:

我是 clojure 的新手,我刚刚学习并尝试了 memorize 功能。 在我看来这个功能的存在很奇怪。

首先有副作用的函数以!结尾

其次使用memorize很简单

为什么clojure 不只是为我做这个?内存使用和性能之间存在平衡,但您可以轻松地让 clojure 运行时将一大块 ram 分配给函数结果。如果使用相同的参数多次调用一个函数,则使用缓存结果,如果内存耗尽,则清除缓存并跟踪缓存命中,因此频繁调用的函数不太可能从缓存中删除。

如果我设计了这个,我什至会为函数设置一个最低性能级别,这样如果函数调用比缓存检索更快,它就不会被缓存。 (或者让它成为所有函数调用如何工作的属性。)

谁能解释为什么clojure不这样做

谢谢

【问题讨论】:

  • 如果您可以将此功能添加到编译器中,您会为 Clojure 社区感到高兴。请记住,Clojure(不像 - 比如说 - Haskell)不会强制函数是纯函数。
  • 我认为没有人会对此感到高兴。它有很多问题。您几乎会立即填满内存,例如,缓存一堆没人关心的无用垃圾,没有空间缓存一两个有用的东西。此外,您会为每个函数调用添加大量开销以进行缓存,并测量“最低性能水平”以确定事物是否值得缓存。性能将变得更加难以推理,因为每个函数的运行时都变得不确定。副作用函数运行“如果感觉喜欢”。

标签: clojure


【解决方案1】:

计算机科学界有个老笑话说只有两个难题:

  1. 缓存失效
  2. 给事物命名

内置的memoize 函数是一个很好的开始,它在某些情况下很有用且足够。然而,它确实很适合上面的那个笑话。这是一个有点尴尬的名字(这里的意见),它在缓存失效时非常失败。它假设如果一个函数曾经被调用过,结果总是相关的,并且该函数是纯的,不会遇到错误,并且所有调用在所有时间都是同等相关的。现实世界充满了对缓存非常重要的细微差别:

  1. 许多返回值不会永远有用
  2. 许多函数的范围是无限的(例如数学)
  3. 许多函数比缓存更快(再次数学)
  4. 函数具有等效参数。它们应该在同一个类中。
  5. memoize 实际上并不能保证只运行一次函数。
  6. 许多函数永远不会是纯函数(例如接受网络连接)
  7. 某些参数不影响返回值。

例如,在为 Web 应用程序设计缓存时,所有这些事情都会发挥作用。 #5 是一个有趣的案例,考虑一下如果你 memoize 一个非常慢的函数,并且相隔一秒有两次调用它会发生什么。哪个返回值成为记忆的结果?在什么情况下这很重要。这些细节真的很重要,尤其是其中一个遇到不寻常的情况时。

在过去的八年里,我在专业从事 clojure 的工作中似乎多次在生产中使用 memoize,一旦出现不可避免的问题,它总是被调用 clojure.core.cache 中的一个函数在短时间内替换掉。

如果你发现自己想要memoize 很有可能你会更喜欢 core.cache。它提供了更多细致入微的选项,以适应更多真实案例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 2022-01-14
    • 1970-01-01
    相关资源
    最近更新 更多