在我的实践中,使用三元比较运算符(例如检查一个数字是否在范围内)非常常见。
(< 0 temp 100)
问题是,与 {{(and (< 0 temp) (< temp 100))}} 相比,它几乎慢了三倍。
这是因为三元arity是通过通用vararg arity分支处理的
(defn <
"如果数字按单调递增顺序排列,则返回非nil,否则返回false。"
{:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (lt x y)))
([x y & more]
(if (< x y)
(if (next more)
(recur y (first more) (next more))
(< y (first more)))
false)
false)
此补丁为这些函数添加对三元arity的特殊处理:{{< <= > >= = == not=}}
(defn <
"如果数字按单调递增顺序排列,则返回非nil,否则返回false。"
{:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y)))
:inline-arities #{2}
:added "1.0"}
([x] true)
([x y] (. clojure.lang.Numbers (lt x y)))
([x y & more]
([x y z] (and (. clojure.lang.Numbers (lt x y))
(. clojure.lang.Numbers (lt y z))))
([x y z & more]
(if (< x y)
(let [nmore (next more)]
(if nmore
(recur y z (first more) nmore)
(< y z (first more))))
false)))
性能提升相当显著
(= 5 5 5) 24.508635 纳秒 => 4.802783 纳秒 (-80%)
(not= 1 2 3) 122.085793 纳秒 => 21.828776 纳秒 (-82%)
(< 1 2 3) 30.842993 纳秒 => 6.714757 纳秒 (-78%)
(<= 1 2 2) 30.712399 纳秒 => 6.011326 纳秒 (-80%)
(> 3 2 1) 22.577751 纳秒 => 6.893885 纳秒 (-69%)
(>= 3 2 2) 21.593219 纳秒 => 6.233540 纳秒 (-71%)
(== 5 5 5) 19.700540 纳秒 => 6.066265 纳秒 (-69%)
更高阶arity也变得更快,主要是因为现在有一个更少的迭代次数。
(= 5 5 5 5) 50.264580 纳秒 => 31.361655 纳秒 (-37%)
(< 1 2 3 4) 68.059758 纳秒 => 43.684409 纳秒 (-35%)
(<= 1 2 2 4) 65.653826 纳秒 => 45.194730 纳秒 (-31%)
(> 3 2 1 0) 119.239733 纳秒 => 44.305519 纳秒 (-62%)
(>= 3 2 2 0) 65.738453 纳秒 => 44.037442 纳秒 (-33%)
(== 5 5 5 5) 50.773521 纳秒 => 33.725097 纳秒 (-33%)
此补丁还更改了{{not=}}的变长参数形式,改为使用next/recur而不是{{apply}}
(defn not=
"与(not (= obj1 obj2))相同"
{:tag Boolean
:added "1.0"
:static true}
([x] false)
([x y] (not (= x y)))
([x y z] (not (= x y z)))
([x y z & more]
(if (= x y)
(let [nmore (next more)]
(if nmore
(recur y z (first more) nmore)
(not= y z (first more))))
true)))
结果很好
(not= 1 2 3 4) 130.517439 ns => 29.675640 ns (-77%)
我在这里也想像CLJ-1912中的[~wagjo]一样,只计算一次{{(next more)}},虽然仅仅这样做性能提升并不大。
我的观点是,优化三参数函数是有意义的,因为它们在真实代码中出现的频率相当高。参数更多(4个及以上)的函数应用较少。