Programming Language Roam: Load-Time Calculation
「加载期计算」,是指: 在代码加载时执行运算或者这种能力 和 编译期计算 相比,加载期计算可能适用范围更广 场景 加载期计算主要适用于以下的场景: 程序运行时需要的某些信息,如环境变量等,无法在编译期间确定 这些信息在程序启动后几乎不会发生变化 程序运行时需要根据不同的环境信息,执行不同的运算 比较典型的场景就是跨平台应用,以及使用静态配置的应用,这些应用在真正运行前是无法获得目标平台、或者目标配置的 值。而运行后,要么对这些信息进行缓存以便反复使用,要么就是每次使用这些信息时,都重新进行一次读取/查询。 而如果程序支持「加载期计算」,则可以在代码加载时,读取相关信息,然后直接将信息写入到调用的代码处,甚至,可以根据 信息的值来选择性生成不同的处理代码。 这样,对于程序而言,这些信息就变成了静态的常量了,且无用的代码分支也会被裁剪掉,这样就减少了程序在缓存、调用、 分支预测上的开销了 Load-Time Hook/Callback 部分语言,比如 Erlang、C#(Unity) 等支持在模块、类、程序集加载时,执行某个函数,这种行为可以看作是代码加载时的一个 回调,或者说是一种受限的「加载期计算」,因为这样的计算,执行的都是编译期已经生成好的代码,无法通过在加载期间执行的运算来影响到原有的代码逻辑。 C# (.Net) 可以在加载时,找到对应属性的程序集、类、方法、乃至字段等,然后动态修改、生成代码。 这种操作,可以算是在代码加载期间执行的 JIT 操作,而「加载期计算」更多的是强调「计算」或者说 「求值」, 但总的来说,区别不大,可以看作是一回事。 示例,零开销配置 这里做一个简单的演示,使用 message 文本文件做为配置文件,里面的内容为: Hello, World! 定义函数 get-message ,直接读取整个文本文件,当作是配置读取操作: (defun get-message () (uiop:read-file-string "~/message")) 定义函数 test , 直接使用 get-message 模拟读取配置操作 (defun test () (let ((msg (get-message))) msg)) 为了防止编译器优化,这里写的很啰嗦,第三行的 msg 实际上可以看作是具体的配置操作过程,只是这里简单的用返回这个行为 来模拟 定义一个函数 test2 , 使用加载期计算,在代码加载时,求出 get-message 的值,然后直接写入到 test2 的代码内...