繁体   English   中英

JVM Clojure的Protcols实现如何工作?

[英]How does JVM Clojure's implementation of Protcols work?

有关Clojure 协议的文档指出,为每个协议都生成了相应的Java接口。 但是,您可以使用协议进行的操作(将它们扩展为任意类型等)在Java接口方面似乎并不能直接实现。 协议和协议方法在内部如何工作? 为什么以及每个协议都需要Java接口?

对Clojure平台源代码的简要检查显示:

  1. 对于每种协议方法,都有一个哈希表,该哈希表从Java Class映射到实现Class的协议的Clojure函数。 (它实际上是一个名为MethodImplCache的自定义类的实例。)
  2. 调用协议方法的调度函数时,它将获取Class一个参数的Class并在哈希表中进行查找。
  3. 如果找不到任何内容,它将遍历第一个参数的继承链,直到找到查找成功的超类。 然后它将调度Class插入哈希表中,以便下次可以直接找到它。
  4. 此外,每当查找成功时,最新发现的Class及其对应的方法实现都将缓存在一个实例变量中,如果下次分配的Class相同,则用于绕过哈希查找。
  5. 当协议扩展到任意Java类时,生成的接口将不会发挥任何作用。 如上所述,使用MethodImplCache可以解决对协议方法的调用。
  6. 当您使用生成的接口用于reify得到延伸的协议,或者如果您使用匿名类的实例deftypedefrecord进行延伸的协议的新类。 在任何一种情况下,您都将获得实现所生成接口的Class对象。
  7. 当Clojure编译器发出JVM字节码以调用协议方法时,它会插入一些字节码,以检查第一个参数是否为所生成接口的实例。 如果是这样,它将对接口的适当方法使用普通的Java方法调用。 在那种情况下,我上面描述的协议调度功能将被完全绕过,并且永远不会被调用。

所有这些似乎都暗示着,当扩展到任意类时,协议方法调用应该比普通的Clojure函数调用慢。 如果您defrecord联方式扩展协议,则与reify / deftype / defrecord一起使用时的性能应该要好得多,而不是单独调用extend-protocolextend-type

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM