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

如果有的话,我怎样才能提高我在Clojure中的数值性能?

  •  4
  • mac01021  · 技术社区  · 6 年前

    下面是一个简短的Scala程序,它通过生成一组随机数来计算欧拉数的近似值:

    package example
    
    import scala.util.Random
    
    object ApproxE extends App {
    
       def calc = {
         var S = 0.0
         for {i <- 1 to 100000000} {
           var x = 0.0
           var t = 0
           while (x <= 1.0) {
             x += Random.nextDouble
             t += 1
           }
           S += t
         }
         S / 100000000
      }
    
      val st = System.currentTimeMillis()
      val e = calc
      val ed = System.currentTimeMillis()
    
      println(e)
      println(ed - st)
    
    }
    

    在我的笔记本电脑上运行,它在7秒内完成计算。

    在纯Clojure中,是否有可能编写性能与Java或Scala相当的等效程序?

    (defn calc []
        (loop [i (int 0)
               S (double 0.0)]
            (if (= i 100000000)
                (/ S 100000000)
                (let [rs (repeatedly rand)
                      ps (reductions + rs)
                      <=1 #(<= % 1)]
                  (->> ps
                    (take-while <=1)
                    (count)
                    (inc)
                    (+ S)
                    (recur (inc i)))))))
    

    230秒:

    (defn calc2 []
        (with-local-vars [S 0.0]
            (dotimes [i 100000000]
                (with-local-vars [x (double 0)
                                  t (int 0)]
                    (while (<= @x 1)
                        (var-set x (+ @x (rand)))
                        (var-set t (inc @t)))
                    (var-set S (+ @S @t))))
            (/ @S 100000000)))
    
    1 回复  |  直到 6 年前
        1
  •  7
  •   Aleph Aleph    6 年前

    懒惰的数据结构和局部变量都会由于分配而引入开销(尽管您仍然可以通过将分配移到另一个变量来使变量更快一些) x t 循环外)、名称解析(在变量的情况下)和方法调用。

    Scala代码的逐字翻译将使用本地绑定(使用 let loop ),相当于Java的局部变量:

    (defn calc-loops []
      (loop [i (int 0)
             S (double 0.0)]
        (if (= i 100000000)
            (/ S 100000000)
            (recur
             (inc i)
             (loop [t 0 x 0.0]
               (if (<= x 1.0)
                 (recur (inc t) (+ x (rand)))
                 (+ S t)))))))
    
    (time (calc))       ;; => "Elapsed time: 56255.692677 msecs"
    (time (calc-loops)) ;; => "Elapsed time: 8800.746127 msecs"