正如有人所說,刪除dosync似乎改善了10倍,但這不是整個故事。一旦JVM有熱點的代碼,它會得到更快的10倍。這就是爲什麼你應該用嚴格的標準或類似的測試真實世界的速度...
(def number (atom 0))
(defn tak [x y z]
(if (<= x y)
y
(do
(swap! number inc)
(tak (tak (dec x) y z)
(tak (dec y) z x)
(tak (dec z) x y)))))
(defn takeuchi_number [n]
(reset! number 0)
(tak n 0 (inc n))
@number)
;=> (time (takeuchi_number 10))
; "Elapsed time: 450.028 msecs"
; 1029803
;=> (time (takeuchi_number 10))
; "Elapsed time: 42.008 msecs"
; 1029803
原件dosync對我的機器上5秒,所以我們基地的兩個數量級10的時候已經!這是我們能做的最好的嗎?讓我們重構純粹的功能,擺脫櫃檯。
(defn tak [c x y z]
(if (<= x y)
[c y]
(let [[a- x-] (tak 0 (dec x) y z)
[b- y-] (tak 0 (dec y) z x)
[c- z-] (tak 0 (dec z) x y)]
(recur (+' 1 a- b- c- c) x- y- z-))))
(defn takeuchi_number [n]
(tak 0 n 0 (inc n)))
;=> (time (takeuchi_number 10))
; "Elapsed time: 330.741 msecs"
; [1029803 11]
;=> (time (takeuchi_number 10))
; "Elapsed time: 137.829 msecs"
; [1029803 11]
;=> (time (takeuchi_number 10))
; "Elapsed time: 136.866 msecs"
; [1029803 11]
不太好。在向量中保持狀態並傳遞它的成本可能是一個開銷。然而,現在我們已經重構純度,讓我們利用我們的良好行爲!
=> (def tak (memoize tak))
#'euler.tak/tak
=> (time (takeuchi_number 10))
"Elapsed time: 1.401 msecs"
[1029803 11]
健康快3000倍左右。適用於我。
您是否需要將其作爲該函數在其生命期中調用的度量標準,或者是否希望將此數字與結果一起使用?對於後來的這個appropach會是錯誤的(併發調用)並傳遞它(例如作爲元)會更好。 – cfrick
刪除'dosync'-你不需要交換原子 - 增加我的運行時間因子5. – Jens
我的意思是減少;-) – Jens