目前,启用直接链接(DL)的方法大多是全有或全无,带有精细的拒绝选择(`^:redef`)。据我所知,这使得在生产环境中使用DL有些笨拙,您仍然想要保留调试和调查应用程序的能力。事先知道需要重新编译哪些函数是繁琐且精神负担很大的。事实上,我最终由于这个原因完全没有启用DL。
我想知道是否有更灵活的方式来调整DL是否会使其更受欢迎。以下是我对此的一些想法。
当前,是否要执行DL的决定是在调用位置根据编译时该调用位置的`*compiler-options*`的值做出的。我设想的一种替代方案是,当决定DL是在函数定义时间做出时,并且该函数未来的所有调用都尊重这个决定。
让我给你举一个例子。Clojure自身通过启用DL来编译`clojure.core`命名空间。这意味着`clojure.core`中的函数会静态地链接到其他`clojure.core`函数。然而,如果开发人员已禁用DL,那么调用`clojure.core`函数将走Var解析。我个人无法想象出一个需要这样精确行为的场景。有人会希望重新定义他们运行时仍然希望某些其他代码使用旧版本的`clojure.core`函数吗?这是否是语言设计想要鼓励的事情?
我的第二个观点是,除了对于在紧密循环中调用的特定函数外,通常DL并不带来相当大的性能提升,这些函数适用于JIT级联优化,因为这会导致内联。这些性能关键函数可以由开发人员通过分析器可靠地识别出来,然后对那些函数只启用DL是有意义的。目前,唯一能确保JIT内联的函数而不需要接受DL整体解决方案的方式是使用半隐秘的`:inline`函数,毕竟这是一种宏。
在实现方面,这可以通过`*compiler-options* :direct-linking`的特殊值(有点类似于`*unchecked-math*`可以是`true`或`:warn-on-boxed`)以及Vars上的元数据来实现(可以重用当前的no-op ^:static
)。
简而言之:我希望有一种DL模式,其中所有用DL编译的函数的调用位置都自动直接链接,并且有一种方式可以显式标记函数始终使用DL。其他人觉得这种功能有用吗?我很乐意听听您的想法。