当前`satisfies?`未使用与协议方法相同的实现缓存,使得它在实际使用中速度太慢。
使用
(defprotocol p (f [_]))
(deftype x [])
(deftype y [])
(extend-type x p (f [_]))
补丁前
(let [s "abc"] (bench (instance? CharSequence s))) ;; 执行时间平均值:1.358360纳秒
(let [x (x.)] (bench (satisfies? p x))) ;; 执行时间平均值:112.649568纳秒
(let [y (y.)] (bench (satisfies? p y))) ;; 执行时间平均值:2.605426微秒
*原因:* `satisfies?`调用`find-protocol-impl`以检查一个对象是否实现协议,这会检查x是否是协议接口的一个实例或者x的类是否是协议的实现之一(或者如果它在会导致这种情况的继承链中)。这个检查相当昂贵,并且没有被缓存。
*建议:* 扩展协议的方法实现缓存,以处理(并缓存)实例检查(包括负结果)。
补丁后
(let [x (x.)] (bench (satisfies? p x))) ;; 执行时间平均值:79.321426纳秒
(let [y (y.)] (bench (satisfies? p y))) ;; 执行时间平均值:77.410858纳秒
*补丁*: CLJ-1814-v7.patch (依赖于CLJ-2426)