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

欢迎!请查看关于页面以获取更多关于如何使用本网站的信息。

0
编译器

目前,启用直接链接(DL)的方法主要是非此即彼的,有点像^:redef的 pinpoint opt-out。根据我的经验,在您仍希望在调试和调查目的中使用此应用程序的情况下,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)和 Var 上的元数据(可以重用当前的 ^:static)来实现。

简而言之:我想要一种 DL 模式,当某个函数的所有调用点编译时自动进行直接链接,并且还有一种方法可以显式标记一个函数始终使用 DL。其他人觉得这样的特性有用吗?非常愿意听到您的想法。

1 个回答

+1 投票

在某些特定点上

有人想在保持旧版本仍被某些其他代码使用的前提下,重新定义他们运行的 clojure.core 函数,会有这样的想法吗?

人们确实会这么做,不管这是一个好主意还是坏主意。《https://github.com/generateme/fastmath》 是一个例子。

我的第二个观点是,简单的直接链接通常只能带来相当微小的性能提升

直接链接不仅仅能带来性能提升(如您所说,通常除了热点循环代码外,并不明显),特别是在不需要加载变量进行链接时,可以显著减少静态初始化器和常量池的大小,从而减小类的尺寸和减少加载时间。在广泛范围内进行重复链接会使这一点变得显著(clojure.core 特别庞大,这一点在这里得到了放大)。如果我们添加懒变量加载,那么加上重复链接将进一步提高这一点。

话虽如此,我认为可能有更多针对重复链接进行定向使用的方法,向函数的消费者发出信号可能是有益的(类似于 ^:redef 的反方向 - “请重复链接我”)。但是,我认为最好是从 “我正在尝试做X但做不到” 的角度来处理这件事,我没有听到这方面的请求。或者另一个问题 - 为什么不使用它可以使用的重复链接?这可能是由于对重复链接缺乏了解,或者是因为它与其他特性或工作流程不兼容。

感谢您的回答,亚历克斯!

> 特别是,不需要加载变量进行链接,可以显著减少静态初始化器和常量池的大小

这是一个合理的观点,我没有考虑到这一点。

> “我在尝试做X但做不到”

我将重新说明我的两个用例。

1. 我想确保我的某些函数始终直接链接,这样它们就可以保持内联状态(例如,使用类似于 `^:static` 的元数据)。

2. 我想确保所有 clojure.core 函数始终在 my code 或其他地方进行重复链接。

目前可以通过启用DL(延迟加载)来实现1号和2号目标,但基于我在问题中陈述的原因,我并不想这么做。当然,我的特定需求可能过于具体,因此我创建了此帖,希望能够收集更多关于DL的使用案例。如果有更多,那么这可能有助于找到最合适的方法来扩展对DL的可用控制。
...