使用GraalVM实现java调用python脚本

背景说明

在很多场景下,我们都有从java调用脚本的功能,常用的有groovy脚本,pyhon脚本和js等。在上篇中,列举了java调用pyhton脚本的几种方案,并最终选取了JEP的方式,但是随着业务的提升,JEP由于GIL锁的问题,每次只能执行一次脚本,并发高的情况下,由于资源竞争,JEP会变得非常慢,于是需要新的方案来解决这个问题。

GraalVM介绍

通过查阅资料,找到了一种可行的方案,首先我们了解下什么是GraalVM

GraalVM 是一款基于 Java 虚拟机 (JVM) 的新型全栈虚拟机,由 Oracle 公司开发和维护。GraalVM 除了支持 Java 语言之外,还支持多种编程语言,如 JavaScript、Python、Ruby、R 等。

GraalVM 的主要特点包括:

  • 高性能:GraalVM 基于 JIT (Just-in-time) 编译技术,在运行时动态生成本地代码,可以显著提高程序的性能。
  • 多语言支持:GraalVM 支持多种编程语言,并可以在不同的语言之间进行互操作。
  • 低内存占用:GraalVM 使用了一种名为 GraalVM Native Image 的技术,可以将应用程序编译成本地可执行文件,从而减少内存占用和启动时间。
  • 可扩展性:GraalVM 提供了多种插件和扩展点,可以方便地扩展虚拟机的功能和性能。
  • GraalVM 还提供了多种工具和库,如 GraalVM Compiler、GraalVM Truffle、GraalVM Polyglot 等,可以帮助开发人员更好地使用和优化 GraalVM。

使用GraalVM实现python脚本

GraalPython 是基于 GraalVM 平台的 Python 解释器,由 Oracle 公司和社区开发维护。它支持 Python 3.7 语言规范,并且与 CPython 兼容,可以运行大部分的 Python 代码。

GraalPython 的主要特点包括:

  • 高性能:GraalPython 使用了 GraalVM 平台的 JIT 编译器技术,可以将 Python 代码编译成本地代码,提高程序的执行效率。
  • 多语言互操作:GraalPython 支持 GraalVM 平台的 Polyglot API,可以与其他编程语言进行互操作。
  • 执行安全:GraalPython 支持沙箱机制,可以限制 Python 代码的访问权限,保证执行安全。
  • 可扩展性:GraalPython 提供了多种扩展点和插件机制,可以方便地扩展其功能和性能。
    GraalPython 与 CPython 之间的差异主要在于其内部实现机制。GraalPython 使用了 GraalVM 平台的 Truffle 框架,将 Python 代码转换为 AST (抽象语法树) 并进行优化,然后使用 JIT 编译器生成本地代码。相比之下,CPython 是使用 C 语言实现的,其执行速度较慢,但兼容性更好,可以运行大部分的 Python 代码。

需要使用GraalPython,我们首先要搭建GraalPython环境
安装 GraalVM:下载 GraalVM 安装包并解压缩,然后将其添加到环境变量中。可以参考官方文档:https://www.graalvm.org/docs/getting-started/linux/。

安装 GraalPython:打开终端,执行以下命令安装 GraalPython:

gu install python

该命令会自动安装最新版本的 GraalPython。
验证 GraalPython:执行以下命令验证 GraalPython 是否安装成功:

python --version

如果输出 Python 的版本信息,则说明 GraalPython 安装成功。

使用 GraalPython:在终端中执行以下命令启动 GraalPython 解释器:

graalpython

然后就可以在 GraalPython 环境中运行 Python 代码了。

安装好GraalPython后,我们需要构建venv环境, venv是 Python 3 自带的一个标准库,它可以帮助用户创建虚拟环境,使得不同的项目之间的依赖关系和库版本隔离开来,从而避免了不同项目之间的库冲突和版本不兼容等问题。

使用 venv 创建虚拟环境非常简单,可以按照以下步骤操作:

打开终端,进入项目的根目录,执行以下命令创建虚拟环境:

graalpy -m venv /home/appuser/venv

上述命令将在当前目录下创建名为 myenv 的虚拟环境。

激活虚拟环境:执行以下命令激活虚拟环境:

source /home/appuser/venv/bin/activate

执行上述命令后,终端的提示符会变为 (myenv),表示虚拟环境已经激活。
在这里插入图片描述

在虚拟环境中安装依赖:执行以下命令安装需要的依赖:

pip install package_name

在虚拟环境中安装的依赖包仅对当前项目有效,不会影响系统中的其他项目。

退出虚拟环境:执行以下命令退出虚拟环境:

deactivate

执行上述命令后,终端的提示符会恢复为原来的样子。

需要注意的是,每次进入项目的开发环境时,都需要激活虚拟环境,否则无法使用虚拟环境中的依赖和库。

环境准备好后,我们就可以使用java环境调用python脚本。

  1. 首先导入sdk包
        <dependency>
            <groupId>org.graalvm.sdk</groupId>
            <artifactId>graal-sdk</artifactId>
            <version>22.3.1</version>
        </dependency>
  1. 然后编写代码
    private static final String PYTHON = "python";
    private static final String PYTHON_PYTHON_PATH = "python.PythonPath";
    private static final String PYTHON_EXECUTABLE = "python.Executable";
    private static final String PYTHON_FORCE_IMPORT_SITE = "python.ForceImportSite";
    
    private static Context createContext(String modulePath){
        Engine engine = Engine.create();
        Context context =  Context.newBuilder(PYTHON).allowAllAccess(true).engine(engine)
            .option(PYTHON_FORCE_IMPORT_SITE, "true")
            .option(PYTHON_PYTHON_PATH, modulePath)
            .option(PYTHON_EXECUTABLE, customizeConfig.getPythonExecutable())
            .build();
        return context;
    }

    public static void main(String[] args) {
        Context context = createContext();
        Value bindings = context.getBindings(PYTHON);
        bindings.putMember("a", 1);
        bindings.putMember("b", 2);
        int i = context.eval(PYTHON, "a+b").asInt();
        System.out.println(i);
    }

讲解下关键参数:

  • python.PythonPath 导入外部py文件目录的地址,比如a/a.py
  • python.Executable隔离环境的地址,上文中的/home/appuser/venv
  • python.ForceImportSite 强制开启site,这个功能主要是需要使用第三方库,如requests,则需要在这配置参数,开启sitespackge目录,当然,我们也可以通过脚本中运行”import site“开启。

至此我们通过graalpy实现了java中调用python脚本,在测试过程中,当我们不适用三方库的时候,性能比较客观,但是当我们使用ForceImportSite后性能有显著下降,当然整体比JEP好很多。

坑点

在预言过程中发现每次创建上下文Context非常耗时,一次执行就需要4s多,后来才支持因为cpu内核导致的,我使用的环境是mac m1,下载使用的事GraalVM(amd64),而m1以上的需要下载GraalVM(aarch64)版本,更改后瞬间将速度提升到毫秒级别。
当然GraalVM针对python的试验阶段,一旦能适用,几乎可以毫无成本的引入js脚本的支持,平台引入这个工具具有很高的扩展性
另外,目前对于第三方库python库的支持不是特别兼容,需要继续摸索
官方支持的兼容包如下:

Cython
Keras_preprocessing
Markdown
Pillow
PyYAML
Werkzeug
absl_py
astor
atomicwrites
attrs
cassowary
certifi
chardet
cppy
cycler
dateutil
gast
h5py
hypothesis
idna
joblib
kiwisolver
lightfm
matplotlib
mock
more_itertools
numpy
packaging
pandas
pkgconfig
pluggy
protobuf
py
pybind11
pyparsing
pytest
pytest_parallel
python_dateutil
pythran
pytz
requests
scikit_learn
scipy
setuptools
setuptools_scm
six
sortedcontainers
threadpoolctl
tox
urllib3
wcwidth
wheel
zipp

总结

是否使用GraalVM举要根据自己具体的使用场景去评估,如果只是简单的脚本调用就非常适合,性能客观,但是存在大量的第三方库和自定义库性能就会收到影响,同事需要考虑兼容问题。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值