代码之家  ›  专栏  ›  技术社区  ›  edbond

Clojure:超出GC开销限制,延迟计算,PI序列

  •  5
  • edbond  · 技术社区  · 14 年前

    对于下一个代码:

    (ns clojure101.series)
    
    (defn avg [[x y]] (/ (+ x y) 2))
    
    (defn avg-damp
      [seq]
      (map avg (partition 2 seq)))
    
    (defn avg-damp-n
      [n]
      (apply comp (repeat n avg-damp)))
    
    (defn sums
      [seq]
      (reductions + seq))
    
    (defn Gregory-Leibniz-n
      [n]
      (/ (Math/pow -1 n) (inc (* 2 n))))
    
    (def Gregory-Leibniz-pi
         (map #(* 4 (Gregory-Leibniz-n %)) (iterate inc 0)))
    
    (println (first ((avg-damp-n 10) (sums Gregory-Leibniz-pi))))
    

    对于n=20,我得到“超过GC开销限制”的错误。 我怎么修这个?

    更新 :我更改了avg-damp-n函数

    (defn avg-damp-n
      [n seq]
      (if (= n 0) seq
          (recur (dec n) (avg-damp seq))))
    

    现在我可以得到n=20的数字

    (time
     (let [n 20]
       (println n (first (avg-damp-n n (sums Gregory-Leibniz-pi))))))
    
    20 3.141593197943081
    "Elapsed time: 3705.821263 msecs"
    

    更新2 我修正了一些错误,现在它工作得很好:

    (ns clojure101.series)
    
    (defn avg [[x y]] (/ (+ x y) 2))
    
    (defn avg-damp
      [seq]
      (map avg (partition 2 1 seq)))
    
    (defn avg-damp-n
      [n]
      (apply comp (repeat n avg-damp)))
    
    (defn sums
      [seq]
      (reductions + seq))
    
    (defn Gregory-Leibniz-n
      [n]
      (/ (int (Math/pow -1 n)) (inc (* 2 n))))
    
    (def Gregory-Leibniz-pi
         (map #(* 4 (Gregory-Leibniz-n %)) (range)))
    
    ; π = 3.14159265358979323846264338327950288419716939937510...
    
    (time
     (let [n 100]
       (println n (double (first ((avg-damp-n n) (sums Gregory-Leibniz-pi)))))))
    

    输出:

    100 3.141592653589793
    "Elapsed time: 239.253227 msecs"
    
    3 回复  |  直到 14 年前
        1
  •  2
  •   kotarak    14 年前

    隐马尔可夫模型。。。这对我有用。在Windows XP上使用Clojure 1.2进行测试。

    user=> (defn avg
             [xs & {:keys [n] :or {n 2}}]
             (/ (reduce + xs) n))
    #'user/avg
    user=> (defn Gregory-Leibniz-n
             [n]
             (/ (Math/pow -1 n) (inc (+ n n))))
    #'user/Gregory-Leibniz-n
    user=> (->> (range)
             (map #(* 4 (Gregory-Leibniz-n %)))
             (reductions +)
             (partition 20)
             (map #(avg % :n 20))
             first
             println)
    3.1689144018345354
    

    这是正确的答案吗?我不知道格雷戈里·莱布尼兹的递归,所以我 不确定这是否正确。

    我注意到一点:你太聪明了。也就是你的avg-damp-n 将lazy seq堆叠到lazy seq上。因为你可以插入任意值 n , 您迟早也会遇到堆栈溢出 n 在里面 这种情况。如果有一个直接的解决方案,你应该更喜欢 它。不过,我不确定这是你的实际问题。(就像我说的:相反 对我没用。)

        2
  •  3
  •   Community CDub    8 年前

    正如Kotarak所说,在lazy seq上堆叠lazy seq的效率似乎相当低。 关于GC。我可以在慢原子系统上重现这个问题。参见:

    Error java.lang.OutOfMemoryError: GC overhead limit exceeded

    对于我来说,gregory leibniz pi cacululation直接转换成只使用一个惰性序列的clojure代码:

    (defn Gregory-Leibniz-pi [n]
      (->> (range n)
           (map (fn [n] (/ (Math/pow -1 n) (inc (* 2 n)))))
           (apply +)
           (* 4)))
    
        3
  •  2
  •   ellisbben    14 年前

    首先,尝试一下愚蠢的解决方案:增加你的Java堆空间。

    ;in your clojure launch script
    java -Xmx2G ...other options...
    

    程序的一个部分在分区中不是懒惰的,而是将其更改为懒惰的(通过取消对 count )仍然为默认堆大小提供OutOfMemoryError。将avg-damp-n的聪明度替换为

    (take (integer-exponent 2 20) seq)
    

    仍然会导致内存不足错误。看看其他所有东西的来源,我看不到任何其他东西,它们看起来像是在消耗堆。