2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页面了解有关此功能的更多信息。

+13
协议
目前 `satisfies?` 没有使用与协议方法相同的实现缓存,这使得它在实际应用中运行得太慢。

使用

(defprotocol p (f [_]))
(deftype x [])
(deftype y [])
(extend-type x p (f [_]))


修补前的版本

(let [s "abc"] (bench (instance? CharSequence s))) ;; 执行时间平均值:1.358360 ns
(let [x (x.)] (bench (satisfies? p x))) ;; 执行时间平均值:112.649568 ns
(let [y (y.)] (bench (satisfies? p y))) ;; 执行时间平均值:2.605426 µs


*原因*:`satisfies?` 调用 `find-protocol-impl` 来查看一个对象是否实现了协议,它会检查 x 是否是协议接口的实例,或者 x 的类是否是协议实现的之一(或者它是否在继承链中,这将使此条件为真)。此检查相当昂贵,并且没有缓存。

*建议*:将协议的方法实现缓存扩展到同时处理(和缓存)实例检查(包括负结果)。

修补后的版本

(let [x (x.)] (bench (satisfies? p x))) ;; 执行时间平均值:79.321426 ns
(let [y (y.)] (bench (satisfies? p y))) ;; 执行时间平均值:77.410858 ns


*补丁*:CLJ-1814-v7.patch (依赖于 CLJ-2426)

25 答案

0

评论者:bronsa

这不太好,我会在今天晚些时候查看,谢谢

0

评论者:bronsa

这是关于 nil 缓存的一个问题,我决定为 nil 专门处理以跳过方法缓存,移除所有 NIL 古怪的行为,并修复了 falsenil 之间的糟糕交互。

0

评论者:michaelblume

不确定这是否包含在此工单范围内,但鉴于这未被捕捉,可能应该有更多的协议调度测试。

0

评论者:alexmiller

是的,一定应该添加。

0

评论者:michaelblume

包含测试的补丁

0

评论者:michaelblume

验证了测试在v4补丁中失败

`

 [java] Testing clojure.test-clojure.protocols
 [java]
 [java] FAIL in (test-default-dispatch) (protocols.clj:695)
 [java] expected: (= "Object impl" (test-dispatch false))
 [java]   actual: (not (= "Object impl" "Nil impl"))
 [java]
 [java] FAIL in (test-default-dispatch) (protocols.clj:695)
 [java] expected: (= "Object impl" (test-dispatch true))
 [java]   actual: (not (= "Object impl" "Nil impl"))

`

0

评论者:michaelblume

这个补丁错过了1.9系列吗?我们希望能对HoneySQL进行修复,但我觉得使用satisfies进行的修复恐怕难以进行,因为它的速度很慢。

0

评论者:alexmiller

不一定。在1.9之后,我们不添加新功能,但像这种情况的优化是可能的。它已经通过Rich的审查。它在我的待审查清单中。

0

评论者:bronsa

更新补丁以在基于实例的协议调度之后工作,这个工单应该先等待CLJ-2426。

0
参考:https://clojure.atlassian.net/browse/CLJ-1814(由 bronsa 报告)
...