目前 `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)