编程与软件开发

如何使用 Numba 加速金融服务中的计算型 Python 模型

Milliman 的 Chad Schuster 介绍了 Numba 如何通过 LLVM 将 Python 程序的部分代码转换为优化代码,并利用并行处理和 GPU。该实践展示了显著的性能提升,但也暴露出面向对象编程、类型推断和编译时间方面的限制,因此选择合适的加速部分至关重要。

2026-08-27
2 分钟阅读
13 浏览量
فريق تحرير certi.news
如何使用 Numba 加速金融服务中的计算型 Python 模型

Milliman 金融风险管理业务的 Principal Chad Schuster 分享了使用 Python 和 Numba 构建高性能计算模型的实践,而不是完全依赖使用 C++ 编写的应用程序。该实践源于金融服务领域一个常见的问题:通过大量情景模拟现金流的模型需要强大的计算能力,而团队又希望保留 Python 的开发速度和易维护性。

这一问题在寿险模型和年金(annuities)等退休产品中尤其重要,因为这些计算用于评估未来负债并运行多种情景。演讲指出,保险公司过去曾依赖包含 5,000 至 10,000 个节点的本地集群,但迁移到云端后,每次运行的时间和成本在基础设施决策中变得更加明确。

Numba 为 Python 增加了什么?

传统 Python,即 CPython,会在运行时解释代码,而 C++ 等编译型语言则会在执行前将代码转换为机器指令。Numba 通过即时编译(Just-in-Time)尝试缩小这一差距:它会在程序运行期间使用 LLVM 编译符合条件的函数,然后用编译后的实现替换原始函数。

开发者通常通过 Python 装饰器(如 JITnjit)启用这一过程。Numba 在函数层面工作,会检查代码并将其转换为自身的中间表示,然后推断变量、参数和返回值的类型,接着将该表示降级为 LLVM IR 并执行必要的优化。如果使用不同类型调用函数,Numba 可以针对每组类型创建专门的编译实现,这一机制被称为多态分派(polymorphic dispatch)。

性能收益并非固定数值

在 Schuster 展示的概念验证中,与解释执行的 Python 相比,Numba 使程序速度提升了约 75 倍。在另一个模型中,结果有所不同:将计算密集型计算迁移到 CPU 上的 Numba 后,速度提升约一倍;随后迁移到 GPU,在该次特定运行中又实现了 750 倍的额外加速。演讲指出,这一提升水平使一个 GPU 大致相当于该次运行中使用的 750 个内核,并使估算成本降至约十分之一。

但这些结果并不代表对所有应用的普遍承诺。性能提升取决于可编译代码的比例、计算操作相对于输入输出操作的规模、原生 Python 的效率,以及 LLVM 优化生成代码的能力。此外,GPU 处理并不适合所有算法,因此在重新设计模型前必须先测量实际瓶颈。

对工程团队而言,实践中会发生什么变化?

该实践建议尽可能将数据准备、输入和输出层保留在 Python 中,仅将计算密集型部分迁移到 Numba。这种方法可以缩小重写范围,并保留大部分 Python 环境,同时将优化工作集中在消耗大部分执行时间的函数上。当数值函数数量有限且结构清晰时,Schuster 认为,对于希望继续使用 Python 的团队而言,尝试 Numba 可能是一个直接的选择。

而当将广泛且复杂的逻辑引入 Numba 时,设计和维护成本会增加。该实践采用了 NumPy 数组、元组(tuples)和简单数据结构,因为 Numba 并不支持 Python 的全部特性。提到的限制包括具有灵活类型的字典、异常、上下文管理器、闭包、通过推导式(comprehensions)创建的列表,以及一些常用函数的有限支持,例如 printsortedgetattr

采用前必须考虑的限制

在这一实践中,面向对象编程仍是一个重要弱点。Numba 提供了 jitclassesstructrefs 等实验性功能,以实现类似对象的行为,但这些功能可能在不同版本之间发生变化,且不支持 GPU,因此不适合团队采用的方法。于是,应用转向了更接近函数式编程的方式和简单数据结构,尽管出于可维护性和向客户交付模型的考虑,面向对象设计原本更受欢迎。

此外,类型推断错误和 lowering 错误可能难以追踪,尤其是在调用层次较多的程序中。错误信息可能指向远离实际问题产生位置的函数。一个实用方法是在需要时使用 JIT 而不是 njit,这样可以暂时停用 Numba,回退到解释执行的 Python 以便调试,然后在生产运行中重新启用加速。

首次调用每个函数时还会产生初始编译时间,而在大范围使用内联(inlining)技术时,这一时间可能进一步增加。可以采用提前编译(Ahead-of-Time)来避免这一延迟,但与即时编译相比,这可能降低代码根据实际设备进行适配的能力。

编辑解读:这一实践的核心价值并不在于 750 倍这一数字本身,而在于将性能测量与模型拆分联系起来的方法。当瓶颈属于计算问题,并且可以隔离在类型和结构清晰的函数中时,Numba 很合适;但如果试图将整个 Python 系统转换为可编译代码,问题可能会从执行缓慢转变为开发和调试复杂。因此,金融和工程团队在将其视为 C++ 的全面替代方案,或将其视为对系统进行更大范围重新设计的替代方案之前,应权衡运行速度、可维护性、编译时间以及 GPU 兼容性。

新闻来源
InfoQ - Architecture Articles
查看原始来源 ↗
ف
作者

فريق تحرير certi.news

同一分类

你可能还喜欢

查看所有新闻