Replace Clojure,替换let绑定中的变量会导致性能问题吗?

Replace Clojure,替换let绑定中的变量会导致性能问题吗?,replace,clojure,binding,var,let,Replace,Clojure,Binding,Var,Let,假设有一个函数,它接收到一个json字符串,其中包含大约100KB的数据。字符串被转换为映射,然后将新键与该映射关联,并替换let绑定中的var,如下所示: (defn myfn [str] (let [j (json/read-str str) j (assoc-in j [:key1 :subkey1] somedata1) j (assoc-in j [:key2 :subkey2] somedata2) .... j

假设有一个函数,它接收到一个json字符串,其中包含大约100KB的数据。字符串被转换为映射,然后将新键与该映射关联,并替换let绑定中的var,如下所示:

(defn myfn
  [str]
  (let [j (json/read-str str)
        j (assoc-in j [:key1 :subkey1] somedata1)
        j (assoc-in j [:key2 :subkey2] somedata2)
        ....
        j (assoc-in j [:key100 :subkey100] somedata100)]
    ... do something ...))
我知道,在所有这些let绑定之后,j将添加所有这些新键。这只是一个例子。我想知道在同一个var的大量绑定中会发生什么

我指的是记忆中发生的事情。那会在内存中复制100KB 100次吗?它会消耗掉100KB*100=10000kb直到它离开这个函数?或者,Clojure足够聪明,它实际上一直在相同的内存空间中添加新的密钥


如果您还可以推荐我应该在Clojure参考中查找的位置来找到这个问题的答案,那将非常好。

Clojure使用一个名为a的数据结构,它类似于树,但只在叶节点上有数据。clojure的大多数持久结构都是作为trie实现的

真正详细地解释了事情并使用了向量,所以我不会在这里重复。我知道S.O.更倾向于给出内容而不是链接,但这不是一个可以在这里的答案中完全涵盖的主题,而这篇文章做得最好,所以我将链接到它

简言之,当以某种方式修改数据结构时,将为新“版本”创建一个新的trie,而不是通过一次更改将所有数据从旧数据复制到新数据,新结构中的节点指向现有数据。以下是上述文章中显示数据共享的可视化:

因此,使用这种结构,我们可以共享数据,但由于它只是一个二进制trie,它可以很快深入,因此查找可能需要很长时间(对于10亿个元素的向量,到达叶节点的深度是log21e9,即30)。为了解决这个问题,clojure使用了32路分支因子而不是2路分支因子,生成的树非常浅。因此,在clojure中包含10亿个元素的向量只需要log321e9,或6个间接层次,就可以到达叶子

我鼓励您阅读这篇文章,并仔细阅读,您将在多个地方看到对
shift+5
的引用。这是一种巧妙的方法,可以使用位移位来索引到trie(log232=5)。有关这方面的详细信息,请参阅


总之,clojure使用高效的数据结构来实现持久性,任何以不变性为核心功能的语言都必须这样做,如果它希望实现可用的性能。

clojure使用一种称为a的数据结构,它类似于树,但只在叶节点上有数据。clojure的大多数持久结构都是作为trie实现的

真正详细地解释了事情并使用了向量,所以我不会在这里重复。我知道S.O.更倾向于给出内容而不是链接,但这不是一个可以在这里的答案中完全涵盖的主题,而这篇文章做得最好,所以我将链接到它

简言之,当以某种方式修改数据结构时,将为新“版本”创建一个新的trie,而不是通过一次更改将所有数据从旧数据复制到新数据,新结构中的节点指向现有数据。以下是上述文章中显示数据共享的可视化:

因此,使用这种结构,我们可以共享数据,但由于它只是一个二进制trie,它可以很快深入,因此查找可能需要很长时间(对于10亿个元素的向量,到达叶节点的深度是log21e9,即30)。为了解决这个问题,clojure使用了32路分支因子而不是2路分支因子,生成的树非常浅。因此,在clojure中包含10亿个元素的向量只需要log321e9,或6个间接层次,就可以到达叶子

我鼓励您阅读这篇文章,并仔细阅读,您将在多个地方看到对
shift+5
的引用。这是一种巧妙的方法,可以使用位移位来索引到trie(log232=5)。有关这方面的详细信息,请参阅


总之,clojure使用高效的数据结构来实现持久性,任何以不变性为核心功能的语言都必须这样做,如果它希望实现可用的性能。

实际上,我经常使用字符串来保持代码干净。我一直在做一些事情来替换绑定中的变量,直到得到最终值,然后在exprs主体中使用该变量。我并不真正关心字符串,但是当我在绑定中处理相当大的映射数据时,这个问题出现了。我不知道内存中实际发生了什么。通常在这种情况下你会使用
->
。也许Clojure可以更好地处理线程最后一个宏。实际上,我经常使用字符串来保持代码整洁。我一直在做一些事情来替换绑定中的变量,直到得到最终值,然后在exprs主体中使用该变量。我并不真正关心字符串,但是当我在绑定中处理相当大的映射数据时,这个问题出现了。我不知道内存中实际发生了什么。通常在这种情况下你会使用
->
。也许Clojure会更好地处理thread last宏。这一系列文章很棒,试图让作者也为关联数据结构做一个。另外:有一个CHAMP实现,它的性能显然相当好或更好。因此,对于我自己的问题,没有100次,甚至没有1次的复制,Clojure可以有效地处理数据结构的更改。因为我一直在替换绑定中的一个var,所以我无法访问旧版本,但绝对不能复制整个数据映射。在所有这些绑定之后,我将可以访问最终版本,该版本包含所有链接到它的值。谢谢,乔希,艺术系列