Почему такая разница в скорости между циклами Clojure и итерационными методами? - PullRequest
5 голосов
/ 26 марта 2012

У меня есть вопрос о том, почему существует такая разница в скорости между методом цикла и методом итерации в clojure.Я следовал этому уроку в http://www.learningclojure.com/2010/02/clojure-dojo-2-what-about-numbers-that.html и определил два метода с квадратным корнем, используя метод Герона:

(defn avg [& nums] (/ (apply + nums) (count nums)))
(defn abs [x] (if (< x 0) (- x) x))
(defn close [a b] (-> a (- b) abs (< 1e-10) ) )

(defn sqrt [num]
  (loop [guess 1]
    (if (close num (* guess guess))
        guess
     (recur (avg guess (/ num guess)))
)))

(time (dotimes [n 10000] (sqrt 10))) ;;"Elapsed time: 1169.502 msecs"


;; Calculation using the iterate method
(defn sqrt2 [number]
    (first (filter #(close number (* % %)) 
        (iterate #(avg % (/ number %)) 1.0))))

(time (dotimes [n 10000] (sqrt2 10))) ;;"Elapsed time: 184.119 msecs"

Между этими двумя методами скорость увеличивается примерно в 10 раз, и мне интересно, чтопроисходит под поверхностью, чтобы заставить эти два быть настолько заметными?

1 Ответ

5 голосов
/ 26 марта 2012

Ваши результаты удивительны: обычно цикл / рекурсия - самая быстрая конструкция в Clojure для циклов.

Я подозреваю, что JVM JIT разработал умную оптимизацию для метода итерации, но не для цикла /рекурсивная версия.Удивительно, как часто это происходит, когда вы используете чистый функциональный код в Clojure: кажется, что он очень пригоден для оптимизации.

Обратите внимание, что вы можете существенно ускорить обе версии, явно указав double:

(set! *unchecked-math* true)

(defn sqrt [num]
  (loop [guess (double 1)]
    (if (close num (* guess guess))
      guess
      (recur (double (avg guess (/ num guess)))))))

(time (dotimes [n 10000] (sqrt 10)))
=> "Elapsed time: 25.347291 msecs"


(defn sqrt2 [number]
  (let [number (double number)]
    (first (filter #(close number (* % %)) 
      (iterate #(avg % (/ number %)) 1.0)))))

(time (dotimes [n 10000] (sqrt 10)))
=> "Elapsed time: 32.939526 msecs"

Как и ожидалось, версия loop / recur теперь имеет небольшое преимущество.Результаты для Clojure 1.3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...