请在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 投票

评论由: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 报告)
...