DolphinDB即时编译(JIT)详解
本页介绍文章信息与引言背景,并概述 DolphinDB 与其对即时编译(JIT)的引入说明。
Source: https://dolphindb.cn/blogs/24
What this page covers
- JIT 的定义与与编译/解释执行对比。
- DolphinDB 中 JIT 的作用、性能对比与适用场景。
- DolphinDB JIT 的用法、支持范围、缓存机制与局限。
- 类型推导的必要性与失败示例。
- JIT 在隐含波动率、Charm 与 stoploss 等案例中的用法与性能对比。
- 后续版本计划支持的扩展方向。
技能认证特训营第二期报名促销
页面顶部提供活动通知与限时报名链接,并强调专属福利优惠。
- 该活动为“技能认证特训营第二期”。
- 页面提供限时报名链接。
- 活动信息强调专属福利优惠。
DolphinDB即时编译(JIT)详解(文章信息与引言)
本节给出文章标题、作者与发布日期,并引出 DolphinDB 与 JIT 的背景说明。
- 文章作者署名为 Junxi。
- 文章发布日期为 2021-05-18。
- DolphinDB 被描述为高性能分布式时序数据库。
- DolphinDB 从 1.01 版本开始支持即时编译(JIT)。
JIT简介
本节定义即时编译(JIT),对比编译执行与解释执行,并说明 JIT 的效率优势与常见应用。
- 即时编译(JIT)是一种动态编译形式,可提高运行效率。
- 编译执行在运行前将程序翻译为机器码,运行效率较高。
- 解释执行由解释器逐句解释并执行,灵活性强但效率较低。
- JIT 在运行时将代码翻译为机器码,可接近静态编译语言效率。
- PyPy 通过 JIT 改善了解释器性能。
JIT在DolphinDB中的作用(含性能对比与适用场景)
本节说明 DolphinDB 解释执行的开销,阐述 JIT 对循环与分支的加速效果,并用示例对比非JIT、JIT与向量化/内置函数性能。
- DolphinDB 编程语言执行方式为解释执行:语法分析生成语法树后递归执行。
- 在不能向量化时,解释执行成本较高。
- for/while/if-else 的反复函数调用可能十分耗时。
- DolphinDB JIT 可显著提升 for、while、if-else 等语句运行速度。
- JIT 适合无法向量化且对速度要求极高的场景。
如何在DolphinDB中使用JIT(方法、支持范围、缓存与局限)
本节介绍 @jit 的使用方式、支持的语句/运算符/函数、空值处理、JIT函数互调、LLVM 编译成本与缓存机制,以及当前局限。
- 使用方式是在用户自定义函数前一行添加 @jit 标识。
- 调用 JIT 函数时,系统实时编译为机器码后执行。
- JIT 支持 if-else、do-while、for 等语句并支持任意嵌套。
- JIT 支持多种运算符,且实现与非JIT一致。
- JIT 底层依赖 LLVM 实现。
- 同一 JIT 函数与参数类型组合只编译一次并缓存结果。
类型推导
本节解释生成 LLVM IR 前需要类型推导,并通过示例说明推导成功/失败的原因与表现。
- 生成 LLVM IR 之前必须知道脚本中所有变量的类型。
- 类型推导采用局部推导方式逐步确定变量与返回值类型。
- 输入类型不支持或使用未支持函数时,推导可能失败并在运行时抛出异常。
- STRING、pair、tuple 等输入类型示例会触发异常。
实例
本节通过隐含波动率、Greeks(Charm)与止损点(stoploss)示例展示 JIT 用法与性能对比。
- 提供隐含波动率计算相关的 @jit 函数示例(如 GBlackScholes 与 ImpliedVolatility)。
- 隐含波动率示例中,JIT 版本与非 JIT 版本给出性能倍数对比结论。
- Charm(Greeks)示例提供多个 @jit 函数,并给出向量化对照实现。
- Charm 示例对比了 JIT、非 JIT 与向量化实现的耗时差异。
- stoploss 示例提供 JIT、非 JIT 与向量化三种实现并对比耗时。
- stoploss 示例注释表明 break 目前不支持,并给出替代方式。
未来计划
本节列出后续版本计划支持的能力扩展方向。
- 计划支持在 for/do-while 中使用 break/continue。
- 计划支持 dictionary 等结构与 string 等类型。
- 计划支持更多数学统计函数。
- 计划增强类型推导以识别更多内置函数的返回值类型。
- 计划支持为参数、返回值与局部变量声明数据类型。
总结
本节重申 DolphinDB 为自定义函数提供 JIT 以提升循环与分支执行速度,并指出典型适用场景。
- DolphinDB 为自定义函数提供 JIT 能力。
- JIT 可显著提升 for/while/if-else 等语句运行速度。
- JIT 适合无法向量化且对速度要求极高的场景。
- 适用场景示例包括高频因子计算与实时流数据处理。
Facts Index
| Entity | Attribute | Value | Confidence |
|---|---|---|---|
| 技能认证特训营第二期 | status | 正式开启并提供限时报名链接与专属福利优惠 | medium |
| 限时报名链接 | url | https://www.qingsuyun.com/h5/e/217471/5/ | high |
| 文章发布日期 | date | 2021-05-18 | high |
| 文章作者署名 | name | Junxi | high |
| DolphinDB | positioning | 高性能分布式时序数据库,内置丰富的计算功能和强大多范式编程语言 | medium |
| DolphinDB | JIT support introduced | 从 1.01 版本开始支持即时编译(JIT) | high |
| 即时编译(JIT) | definition | 动态编译的一种形式,可提高程序运行效率 | high |
| 编译执行 | characteristics | 程序执行前全部翻译为机器码,运行效率较高;以 C/C++ 为代表 | high |
| 解释执行 | characteristics | 由解释器逐句解释并执行,灵活性强但执行效率较低;以 Python 为代表 | high |
| 即时编译(JIT) | mechanism | 运行时将代码翻译为机器码,可达到与静态编译语言相近的执行效率 | high |
| PyPy | uses JIT for performance | Python 的第三方实现 PyPy 通过 JIT 明显改善了解释器的性能 | medium |
| Java 实现 | uses JIT | 绝大多数 Java 实现依赖 JIT 提高代码运行效率 | medium |
| DolphinDB 编程语言执行方式 | execution_model | 解释执行:运行时先进行语法分析生成语法树,然后递归执行 | high |
| DolphinDB 解释执行成本 | cause | 在不能使用向量化情况下解释成本较高;脚本一次函数调用会转化为多次 C++ 内虚拟函数调用 | high |
| 循环与分支语句在 DolphinDB 中的开销 | performance_issue | for/while/if-else 反复调用函数,十分耗时,某些场景不能满足实时性需求 | high |
| DolphinDB JIT | performance_effect | 显著提高 for、while、if-else 等语句运行速度;适合无法向量化且对速度要求极高场景(如高频因子计算、实时流数据处理) | high |
| do-while 求和示例(无 JIT) | time_ms | timer(100) sum_without_jit(vec) // 120552.740 ms | high |
| do-while 求和示例(JIT) | time_ms | timer(100) sum_with_jit(vec) // 290.065 ms | high |
| 内置 sum 函数求和示例 | time_ms | timer(100) sum(vec) // 48.922 ms | high |
| do-while 求和示例性能倍数 | ratio | 不使用 JIT 的耗时是使用 JIT 的 415 倍 | high |
| 内置 sum 比 JIT 快的原因(无 NULL 时) | reason | JIT 生成代码包含大量 NULL 检查指令;内置 sum 若发现输入 array 没有 NULL 值则会省略该步 | high |
| 内置 sum(加入 NULL 后) | time_ms | vec[100] = NULL; timer(100) sum(vec) // 118.063 ms | high |
| 内置 sum 与 JIT 的相对速度(有 NULL 时) | ratio | 加入 NULL 值后,内置 sum 的速度约为 JIT 的 2.5 倍(更快) | medium |
| 内置 sum 更快的原因(有 NULL 时) | reason | 内置 sum 还进行了手动展开优化 | medium |
| JIT 与向量化的选择建议 | guidance | 若任务可向量化可视情况不使用 JIT;但将循环转为向量化需要技巧(如高频因子生成等应用) | medium |
| 知乎专栏(向量化运算示例) | url | https://zhuanlan.zhihu.com/p/77988657 | high |
| 买卖信号向量化表达式 | example | direction = (iif(...) - iif(...)).ffill().nullFill(0h) | high |
| for 循环改写向量化表达式的可读性 | observation | 对初学者而言,了解 iif 才能写出向量化语句;用 for 循环改写更容易 | medium |
| calculate_with_jit 示例 | uses_jit | 函数定义前使用 @jit,包含 for 循环与 if-else 分支,返回 output array | high |
| 信号计算示例(向量化) | time_ms | timer(100) 向量化表达式 // 41092.019 ms | high |
| 信号计算示例(JIT) | time_ms | timer(100) calculate_with_jit(...) // 17075.127 ms | high |
| 信号计算示例(非 JIT 循环版) | time_ms | timer(100) calculate_without_jit(...) // 1404406.413 ms | high |
| 信号计算示例性能倍数(JIT vs 向量化) | ratio | 使用 JIT 的速度是向量化运算的 2.4 倍 | medium |
| 信号计算示例性能倍数(JIT vs 非JIT) | ratio | 使用 JIT 的速度是不用 JIT 的 82 倍 | high |
| JIT 比向量化更快的原因(该示例) | reason | 向量化调用多次内置函数产生中间结果,涉及多次内存分配与虚拟函数调用;JIT 生成代码没有这些额外开销 | high |
| 期权隐含波动率计算(牛顿法) | vectorization_applicability | 某些计算无法向量化(如牛顿法求隐含波动率),可选择 C++ 插件或使用 JIT | medium |
| DolphinDB 插件链接 | url | https://github.com/dolphindb/DolphinDBPlugin | high |
| 插件与 JIT 的差异 | comparison | 插件:任何场景可用但需 C++ 编写较复杂;JIT:编写更容易但适用场景有限;JIT 速度与 C++ 插件非常接近 | medium |
| DolphinDB JIT 支持范围 | scope | 目前仅支持对用户自定义函数进行 JIT | high |
| DolphinDB JIT 使用方式 | syntax | 在用户自定义函数前一行添加 @jit 标识:@jit def myFunc(/* arguments */) { /* implementation */ } | high |
| DolphinDB JIT 执行方式 | behavior_on_call | 调用 JIT 函数时,系统将函数代码实时编译为机器码后执行 | high |
| DolphinDB JIT 支持的语句 | supported_statements | 赋值、return、if-else、do-while、for;并支持任意嵌套 | high |
| DolphinDB JIT 多重赋值 | not_supported | multiple assign 不支持(示例 a, b = 1, 2 将抛出异常) | high |
| DolphinDB JIT 支持的运算符 | supported_operators | add(+), sub(-), multiply(*), divide(/), and(&&), or(||), bitand(&), bitor(|), bitxor(^), eq(==), neq(!=), ge(>=), gt(>), le(<=), lt(<), neg(-), mod(%), seq(..), at([]);实现与非JIT一致 | high |
| DolphinDB JIT 支持的数学函数 | supported_math_functions | exp, log, sin, asin, cos, acos, tan, atan, abs, ceil, floor, sqrt | high |
| DolphinDB JIT 数学函数调用策略 | implementation_detail | 参数为 scalar 时调用 glibc 对应函数或优化的 C 实现;参数为 array 时调用 DolphinDB 提供的数学函数,以提升效率并减少虚拟函数调用与内存分配 | medium |
| DolphinDB JIT 支持的内置函数 | supported_builtins | take, array, size, isValid, rand, cdfNormal | high |
| JIT 中 array 函数 | constraint | 第一个参数必须直接指定具体数据类型,不能通过变量传递指定;因为 JIT 编译时必须知道所有变量类型,array 返回类型由第一个参数决定 | high |
| JIT 空值处理 | null_handling | JIT 中所有函数和运算符处理空值方法与原生一致:每个数据类型用该类型的最小值表示空值,用户不需专门处理空值 | high |
| JIT 函数之间调用 | supported | JIT 函数可以调用另一个 JIT 函数 | high |
| JIT 函数互调的性能机制 | implementation_detail | 会先编译被调用函数生成 native 函数(示例签名 double myfunc1(double)),调用方机器码直接调用该 native 函数而非运行时判断,以达到最高执行效率 | medium |
| JIT 函数内部调用限制 | not_allowed | JIT 函数内不可以调用非 JIT 的用户自定义函数,因为无法进行类型推导 | high |
| DolphinDB JIT 依赖 | dependency | 底层依赖 LLVM 实现 | high |
| LLVM 官网链接 | url | https://llvm.org/ | high |
| JIT 编译单元 | module_isolation | 每个用户自定义函数编译时生成自己的 module,相互独立 | high |
| JIT 编译步骤 | steps | 初始化 LLVM 相关变量和环境;根据语法树生成 LLVM IR;LLVM 优化 IR 并编译为机器码 | high |
| JIT 编译成本(初始化) | time_ms | 第一步耗时一般在 5ms 以内 | medium |
| JIT 编译成本(总体) | time_ms | 总体编译耗时基本在 50ms 以内(后两步与脚本复杂度成正比) | medium |
| JIT 编译缓存 | compilation_cache | 对于一个 JIT 函数及一个参数类型组合,只编译一次;结果会缓存 | high |
| JIT 缓存查找机制 | mechanism | 根据调用时参数数据类型生成字符串,在哈希表中查找对应编译结果;存在则直接调用,不存在则编译并写入哈希表后执行 | high |
| JIT 适用任务类型 | when_beneficial | 对需要反复执行或运行时间远超编译耗时的任务,JIT 会显著提高运行速度 | high |
| DolphinDB JIT 当前局限(范围) | limitations | 仅支持用户自定义函数 JIT;仅接受 scalar 和 array 参数(table/dict/pair/string/symbol 等暂不支持);不接受 subarray 作为参数 | high |
| 类型推导 | necessity | 使用 LLVM 生成 IR 之前必须知道脚本中所有变量的类型(类型推导步骤) | high |
| DolphinDB JIT 类型推导方式 | approach | 使用局部推导(通过赋值与表达式逐步确定变量与返回值类型) | high |
| 带参数函数的返回类型 | depends_on_input | JIT 函数返回类型可能依赖输入参数类型(示例 foo(x){return x+1}) | high |
| 类型推导失败的结果 | runtime_effect | 函数内部出现不支持类型或输入类型不支持,会导致类型推导失败并在运行时抛出异常 | high |
| JIT 不支持的输入类型示例 | examples | STRING、pair、tuple 等输入会抛出异常(示例 foo("abc"), foo(1:2), foo((1 2, 3 4, 5 6))) | high |
| JIT 不支持的函数导致推导失败示例 | example | cumprod 尚不支持,无法得知返回类型导致类型推导失败(示例 foo 中使用 cumprod) | high |
| 使用 JIT 的建议(类型与函数) | guidance | 避免在函数内或参数中使用 tuple/string 等未支持类型,不要使用尚不支持的函数 | medium |
| 示例:计算隐含波动率(implied volatility) | implemented_with_jit | 提供 GBlackScholes、ImpliedVolatility 与 test_jit 等 @jit 函数示例 | high |
| 隐含波动率示例(JIT 版本) | time_ms | timer(10) test_jit(...) // 2621.73 ms | high |
| 隐含波动率示例(非 JIT 版本) | time_ms | timer(10) test_non_jit(...) // 302714.74 ms | high |
| 隐含波动率示例性能倍数 | ratio | JIT 版本 test_jit 运行速度是非 JIT 版本 test_non_jit 的 115 倍 | high |
| Greeks 风险评估 | context | 量化金融中经常使用 Greeks 进行风险评估;示例以 Charm 展示 JIT 使用 | medium |
| Greeks(finance)参考链接 | url | https://link.zhihu.com/?target=https%3A//www.wikiwand.com/en/Greeks_%28finance%29 | high |
| 示例:计算 Charm(Greeks) | implemented_with_jit | 提供多个 @jit 函数(myMax、NormDist、ND、CalculateCharm、test_jit)并给出向量化对照实现 | high |
| Charm 示例(JIT 版本) | time_ms | timer(10) test_jit(...) // 1834.342 ms | high |
| Charm 示例(非 JIT 版本) | time_ms | timer(10) test_none_jit(...) // 224099.805 ms | high |
| Charm 示例(向量化版本) | time_ms | timer(10) CalculateCharm_vectorized(...) // 3117.761 ms | high |
| Charm 示例性能对比结论 | ratio | JIT 版本比非 JIT 版本快 121 倍左右;比向量化版本快 0.7 倍左右 | medium |
| 知乎专栏(技术信号回测) | url | https://zhuanlan.zhihu.com/p/47236676 | high |
| 示例:计算止损点(stoploss) | implemented_with_jit | 提供 stoploss_JIT、stoploss_no_JIT 与 stoploss_vectorization 三种实现并对比耗时 | high |
| stoploss 示例(JIT 版本) | time_ms | timer(10) stoploss_JIT(...) // 58.674 ms | high |
| stoploss 示例(非 JIT 版本) | time_ms | timer(10) stoploss_no_JIT(...) // 14622.142 ms | high |
| stoploss 示例(向量化版本) | time_ms | timer(10) stoploss_vectorization(...) // 151.884 ms | high |
| stoploss 示例性能倍数 | ratio | JIT 实现比向量化快约 1.5 倍;比非 JIT 快 248 倍左右 | high |
| stoploss 示例中的 break 支持 | not_supported | 示例注释表明 break 目前不支持(通过 i = n 方式替代) | high |
| stoploss 末日触发情形的性能描述 | observation | 若最后一天才触发 stoploss,JIT 版本速度会与向量化一样,但远快于非 JIT | medium |
| 后续版本计划 | roadmap_items | 计划支持:for/do-while 中的 break/continue;dictionary 等结构与 string 等类型;更多数学统计函数;增强类型推导识别更多内置函数返回值类型;支持为参数/返回值/局部变量声明数据类型 | medium |
| 文章总结的核心结论 | conclusion | DolphinDB 为自定义函数提供 JIT,可显著提升 for/while/if-else 等语句运行速度,适合无法向量化且对速度要求极高场景(如高频因子计算、实时流数据处理) | high |