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 提出)
...