Clojure 2024 年度调查 中分享您的想法!

欢迎!请参阅 关于 页面以获取更多关于此功能的信息。

+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
by

评论者:michaelblume

不确定这是否在本工单范围内,但鉴于这个问题没有被捕获,可能需要更多的协议分发测试。

0
by

评论者:alexmiller

是的,确实应该添加。

0
by

评论者:michaelblume

带测试的补丁

0
by

评论者: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
by

评论者:michaelblume

这个补丁错过了1.9版本的火车?我们希望在HoneySQL中进行的修复,我不确定是否应该在satisfies?做,因为它是如此慢。

0
by

评论者:alexmiller

不一定是这样。我们在1.9之后不会添加功能,但是像这样的性能问题是可能的。这对 Rich 来说已经过审查。它在我的待审查事项清单上。

0
>" class="qa-a-item-what" itemprop="url">已回答 by

评论由:bronsa 发布

更新补丁以在新的基于实例的协议分发之后工作,此工单应先等待CLJ-2426。

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