gpt4 book ai didi

clojure - 为什么将它包装在一个函数中需要 10 倍的时间来运行?

转载 作者:行者123 更新时间:2023-12-04 17:32:52 27 4
gpt4 key购买 nike

任何人都可以通过将其包装在一个函数中来解释为什么时间会跳跃一个数量级?

user> (time (loop [n 0 t 0]
(if (= n 10000000)
t
(recur (inc n) (+ t n)))))
"Elapsed time: 29.312145 msecs"
49999995000000

user> (defn tl [r] (loop [n 0 t 0]
(if (= n r)
t
(recur (inc n) (+ t n)))))
#<Var@54dd6004: #object[user$eval3462$tl__3463 0x7d8ba46 "user$eval3462$tl__3463@7d8ba46"]>

user> (time (tl 10000000))
"Elapsed time: 507.333844 msecs"
49999995000000

我很好奇像这样的简单迭代如何可以做得更快。例如,在与此 Clojure 代码相同的系统上,C++ 中类似的迭代循环在 Release 模式下花费不到 1 ms,或在 Debug 模式下花费大约 20 ms。

最佳答案

发生这种情况是因为在第二种情况下传递的参数被装箱。添加类型提示来解决这个问题:

user> (defn tl [^long r]
(loop [n 0 t 0]
(if (= n r)
t
(recur (inc n) (+ t n)))))

user> (time (tl 10000000))
"Elapsed time: 20.268396 msecs"
49999995000000

更新:

1, 2) 在第一种情况下,您使用 java 原语进行操作,这就是它如此之快的原因。 ^Integer在这里不起作用,因为它是盒装类型的类型提示 java.lang.Integer (这就是它大写的原因)。 ^long是 java long 的类型提示原始。对于函数参数,你只能做 ^long^double原始类型提示(除这些之外不支持其他类型提示,您可以为所有类型的原始数组做类型提示,例如 ^floats^bytes 等)。

3) 由于传递的参数被装箱,这会强制所有操作使用通用算术。换句话说,每个 +inc操作将在堆上创建新对象(在基元的情况下,它们将保留在堆栈中)。

更新 2:

作为类型提示的替代方法,您可以在循环之前将传递的参数显式转换为原语:
user> (defn tl [r]
(let [r (long r)]
(loop [n 0 t 0]
(if (= n r)
t
(recur (inc n) (+ t n))))))

user> (time (tl 10000000))
"Elapsed time: 18.907161 msecs"
49999995000000

关于clojure - 为什么将它包装在一个函数中需要 10 倍的时间来运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37298922/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com