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` 的奇怪事务,修复了 `false` 和 `nil` 之间的不良交互。

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 投票
by
参考: https://clojure.atlassian.net/browse/CLJ-1814(由bronsa报告)
...