要实现皮皮调度,那么首先遇到的问题就是:Java和Python如何相互调用,并且Java部分能编译成原生程序。
因为皮皮调度在设计之初就有了明确的目标: (参考皮皮调度(1)——从Airflow到DolphinScheduler,以及“皮皮调度”的来历mp.weixin.qq.com
)Java来实现平台核心框架
Python用来实现各种自定义插件
那让我们来首先列举一下Java和Python互相调用的几种方式
方式1:通过子进程调用Python
这个方式应该是最简单的方式,在Java父进程中,通过ProcessBuilder来启动Python子进程,并重定向子进程的输入输出管道到父进程中。
其优点主要是:相对简单,Java端程序和Python端程序互相隔离,只通过”管道“(pipe)进行通信。
但是其缺点也不少:
首先,Python子进程启动会花费一定时间,这里需要注意,启动python本身是非常快的,但是对于数据处理领域来说,一般python程序都会导入 pandas, numpy等库,而往往 import 这些库就要花费几秒的时间。这就意味着,如果采用子进程调用的方式,那么python中最好做一些较复杂、较耗时的计算,这样才可以使得初始化的几秒的代价显得无足轻重。
而既然”初始化“非常慢,那么,我们自然就会想:是否可以通过多次重用同一个已经完成”冷启动“的子进程来提效呢?
1) 是否可以利用子进程的”输入管道“来不断的发送任务请求,并通过子进程的”输出管道“来接收处理结果。答案是可以的,但是需要注意的是一些细节处理: 比如串行读写管道,比如默认子进程的输出管道是有缓冲的,不一定能及时读取到全部输出。一种比较适合的方式是:父进程分别启动两个单独的线程,一个线程负责发送数据到子进程,另一个线程则专注处理从子进程获取的结果,两个线程之间无需过多进行同步。
2) 子进程也可以使用一些web框架来启动一个HTTP REST服务,这样就不用依赖于比较底层的管道重定向,而是改为REST请求。
但是这些方式都会使得Java和Python之间的通信协议更加复杂。而遵从Unix的设计逻辑,我们最好使得子进程的调用越简单越好: 父进程最好把子进程需要的信息在初始化时就一次性传入(数据小可以直接参数传入,数据大可以通过输入管道传入),然后子进程进行处理并把结果通过管道传给父进程,当任务处理结束,子进程则直接退出。
如何实现这种既架构简单,又初始化快的方式,是值得探索的一个方向。之前曾经想是否可以在Python import完所有module后,把这个时候的程序在内存中的状态存储为一个可执行程序,这样后续的多次运行则避免了每次都重复import的代价,不过目前还没有找到成功的方案。
方式2:GraalVM的多语言混合调用(polyglot)
前文 《GraalVM —— 让Java变得再次强大》 中也提到了GraalVM对于JavaScript和R语言的支持相对还不错,不过对于Python的支持就比较早期(距离能真正使用还有很长的路要走,目前Python基本不可用) (后续文章中我可能也会介绍一下Java 和 Python怎么混合调用)。
GraalVM的远景非常不错,未来有可能能实现更多的语言都在一个进程中无缝集成,不过目前对于Python的支持还非常早期,仍无法使用。
方式3:Jython —— 基于JVM实现的Python平台
Jython项目地址:Jython目前只支持到Python 2.7,对于Python 3.x的支持仍然遥遥无期
Python在数据领域比较火,不光是因为这个语言本身,而更主要的是丰富的生态,这些 CPython的生态无法运行在Jython上,导致Jython无法分到一杯羹
所以,Jython不太适合
方式4:Py4J —— PySpark也在使用的”Java、Python互通桥梁“
Py4J项目地址:
Py4J的特点是:Java和Python分别运行在独立的进程中
首先,需要在Java端启动一个 Gateway Server,并提供一个Java端的Object作为各种功能的入口(Entry Point)
Python端连接Gateway Server,获取到Entry Point对象
接下来Python端就可以从Entry Point切入来远程调用Java端的各种功能, Py4J提供了一系列支持(比如:数据类型序列化、异常处理等),来使得这个”远程调用“的过程方法都仿佛发生在Python中
基于PySpark的广大用户基础,相信Py4J应该是非常稳定的
方式5: Jep —— 基于JNI使得Java无缝调用Python
Jep项目地址:
Jep的好处:Java和Python完全在一个进程中,所需用的资源应该最少
Java和Python的调用就像是函数调用,执行代价很低
PolyNote中使用Jep来使得Notebook的编辑器支持Python代码的快速自动补全,印象非常深刻。
总结
初步看来,要想取得最好的效果,Jep好像是最好的选择,那么我们先来进行Jep的探索之旅吧!