本文结构:
- 需求背景
- 进击的 Python
- Java 和 Python
- 给 Python 加速
- 寻找方向
- Jython?
- Python->Native 代码
- 整体思路
- 实际动手
- 自动化
- 关键问题
- import 的问题
- Python GIL 问题
- 测试效果
- 总结
复制代码
需求背景
进击的 Python
随着人工智能的兴起,Python 这门曾经小众的编程语言可谓是焕发了第二春。
以 tensorflow、pytorch 等为主的机器学习/深度学习的开发框架大行其道,助推了 python 这门曾经以爬虫见长(python 粉别生气)的编程语言在 TIOBE 编程语言排行榜上一路披荆斩棘,坐上前三甲的宝座,仅次于 Java 和 C,将 C++、JavaScript、PHP、C#等一众劲敌斩落马下。
当然,轩辕君向来是不提倡编程语言之间的竞争对比,每一门语言都有自己的优势和劣势,有自己应用的领域。 另一方面,TIOBE 统计的数据也不能代表国内的实际情况,上面的例子只是侧面反映了 Python 这门语言如今的流行程度。
Java 还是 Python
说回咱们的需求上来,如今在不少的企业中,同时存在 Python 研发团队和 Java 研发团队,Python 团队负责人工智能算法开发,而 Java 团队负责算法工程化,将算法能力通过工程化包装提供接口给更上层的应用使用。
可能大家要问了,为什么不直接用 Java 做 AI 开发呢?要弄两个团队。其实,现在包括 TensorFlow 在内的框架都逐渐开始支持 Java 平台,用 Java 做 AI 开发也不是不行(其实已经有不少团队在这样做了),但限于历史原因,做 AI 开发的人本就不多,而这一些人绝大部分都是 Python 技术栈入坑,Python 的 AI 开发生态已经建设的相对完善,所以造成了在很多公司中算法团队和工程化团队不得不使用不同的语言。
现在该抛出本文的重要问题:Java 工程化团队如何调用 Python 的算法能力?
答案基本上只有一个:Python 通过 Django/Flask 等框架启动一个 Web 服务,Java 中通过 Restful API 与之进行交互
上面的方式的确可以解决问题,但随之而来的就是性能问题。尤其是在用户量上升后,大量并发接口访问下,通过网络访问和 Python 的代码执行速度将成为拖累整个项目的瓶颈。
当然,不差钱的公司可以用硬件堆出性能,一个不行,那就多部署几个 Python Web 服务。
那除此之外,有没有更实惠的解决方案呢?这就是这篇文章要讨论的问题。
给 Python 加速
寻找方向
上面的性能瓶颈中,拖累执行速度的原因主要有两个:
- 通过网络访问,不如直接调用内部模块快
- Python 是解释执行,快不起来
众所周知,Python 是一门解释型脚本语言,一般来说,在执行速度上:
解释型语言 < 中间字节码语言 < 本地编译型语言
自然而然,我们要努力的方向也就有两个:
- 能否不通过网络访问,直接本地调用
- Python 不要解释执行
结合上面的两个点,我们的目标也清晰起来:
将 Python 代码转换成 Java 可以直接本地调用的模块
对于 Java 来说,能够本地调用的有两种:
- Java 代码包
- Native 代码模块
其实我们通常所说的 Python 指的是 CPython,也就是由 C 语言开发的解释器来解释执行。而除此之外,除了 C 语言,不少其他编程语言也能够按照 Python 的语言规范开发出虚拟机来解释执行 Python 脚本:
- CPython: C 语言编写的解释器
- Jython: Java 编写的解释器
- IronPython: .NET 平台的解释器
- PyPy: Python 自己编写的解释器(鸡生蛋,蛋生鸡)
Jython?
如果能够在 JVM 中直接执行 Python 脚本,与 Java 业务代码的交互自然是最简单不过。但随后的调研发现,这条路很快就被堵死了:
- 不支持 Python3.0 以上的语法
- python 源码中若引用的第三方库包含 C 语言扩展,将无法提供支持,如 numpy 等
这条路行不通,那还有一条:把 Python 代码转换成 Native 代码块,Java 通过 JNI 的接口形式调用。