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纳秒
(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)

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