请在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 报告)
...