为何功能等效的Python代码运行速度比Clojure代码更快?
Clojure与Python等效递归代码运行速度差异原因解析
问题描述
此前普遍认为Clojure运行速度优于Python,但两段功能等效的递归代码实际运行时,Python版本速度明显更快,差异核心是否来自Python的编译阶段优化?
测试用代码
Python版本
def find_fifty(n,memory=1,count=0): if memory < 0.5: return count else: return find_fifty(n,memory*(1 - count/n),count+1) find_fifty(100000)
初始Clojure版本
(defn fifty ([n] (fifty n 1 0)) ([n memory count] (if (< memory 0.5) count (recur n (* memory (- 1 (/ count n))) (inc count))))) (fifty 100000)
实际运行时Clojure版本耗时随输入规模上升的速度远快于Python,Python可支撑的输入规模上限远高于初始版本的Clojure实现。
性能差异根因
该现象和Python的编译优化没有关系,核心问题出在Clojure默认的数值运算规则上:
- Clojure的
/运算符在输入均为整数时,默认返回精确有理数而非浮点数。随着递归次数增加,有理数的分子、分母会不断膨胀为超大整数,每一轮迭代的乘法、除法运算复杂度都会持续升高,最终导致整体耗时呈非线性增长。 - Python的
/运算符默认返回双精度浮点数,所有运算都是固定开销的浮点计算,不会出现数值膨胀导致的复杂度上升问题。
Clojure优化方案
只需将初始入参强制转换为浮点类型,后续所有运算都会自动变为固定开销的浮点运算,优化后Clojure的运行性能远高于Python版本,可轻松支撑千万级输入规模:
(defn fifty ([n] (fifty (float n) 1 0)) ([n memory count] (if (< memory 0.5) count (recur n (* memory (- 1 (/ count n))) (inc count))))) (fifty 10000000)
内容的提问来源于stack exchange,提问作者Derek Muller
相关产品推荐
相关产品推荐

