【问题标题】:Do large bindings inside a Clojure recursive function harm performance?Clojure 递归函数中的大型绑定会损害性能吗?
【发布时间】:2015-02-07 08:31:40
【问题描述】:

我正在编写一个函数,该函数基于一组声明性规则进行一组转换。这些规则是一个编译时评估的集合(没有函数调用或任何东西)。它们将包含数百个元素。

基本布局如下所示:

(defn dostuff-with-rules [stuff]
  (let [rules [["foo"] ["bar"] ["baz"] ...]
        transformed (reduce apply-rule stuff rules)]
    (if (not= stuff transformed)
      (recur transformed)
      transformed)))) 

我担心为每个函数调用初始化大量数据会损害性能,最好将rules 移到函数范围之外。

这是否有意义,或者 Clojure 是否足够聪明,只需初始化一次规则?或者将loop 放在let 绑定中是否有意义?

编辑:如果这不是一个简单的尾递归,而是一个树遍历,每个节点都递归调用dostuff-with-rules

【问题讨论】:

    标签: performance recursion clojure tail-recursion


    【解决方案1】:

    Clojure(或者更确切地说是编译器和 JVM 的组合)确实足够聪明,不会在循环和循环时重复分配常量,因此在该帐户上遇到问题的风险很小。如果你有一个昂贵的函数来初始化规则并将它放在循环/fn/recur 中,那么它确实会成为一个问题,尽管它很容易修复。

    这里是一个每次都重新计算一个向量的例子:

    user> (time (loop [a 1]
                  (if (< a 4)
                    (let [big (vec (range 10e6))]
                      (do (println (rand-nth big))
                          (recur (inc a)))))))
    9528975
    717854
    729682
    "Elapsed time: 3753.978349 msecs"
    nil
    

    以及引用常量的位置:

    user> (def big (vec (range 10e6)))
    #'user/big
    user> (time (loop [a 1]
                  (if (< a 4)
                    (do (println (rand-nth big))
                        (recur (inc a))))))
    4002962
    7528467
    2596236
    "Elapsed time: 0.685522 msecs"
    nil
    

    因此,如果您将规则放在一个常量中,例如从配置文件中加载它们,那么您将获得快速的性能和有意义的管理它们的方式。

    如果你尝试使用太大的字面值,它确实会失败(在这种情况下,我在宏中生成它)

    user> (defmacro make-big-vec [] (vec (range 10000)))
    #'user/make-big-vec
    user> (time (loop [a 1]
                  (if (< a 4)
                    (let [big (make-big-vec)]
                      (do (println (rand-nth big))
                          (recur (inc a)))))))
    CompilerException java.lang.RuntimeException: Method code too large!, compiling:(/tmp/form-init1716519094506420012.clj:1:7) 
    

    虽然 1000 可以正常工作。

    【讨论】:

      猜你喜欢
      • 2011-10-13
      • 2013-08-15
      • 2010-12-17
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 1970-01-01
      相关资源
      最近更新 更多