
公司想搞 AI 相关的,但老企业用的全是 java ,结果就是要用 java 调 python 。
目前只能搞成 java 调 python 打包的 exe 。
也想过用 JNI-CPython-Python 的思路,但是解决不了 python 依赖大量第三方库的问题,没法把 python 代码包括第三方依赖一起给打包成 so 文件。
想问问有没有技术大佬有啥解决思路或者方案。
1 Nooooobycat 2023-12-26 16:01:30 +08:00 Python 这边集成一个 web 框架,HTTP 请求进来的时候调用 AI 相关的逻辑。 这样别说用 Java ,bash shell 调用都行 |
2 Haku OP @Nooooobycat 这种方案肯定是可行的,但是公司这边这次不让,这次需求上就是不准开端口。 |
3 vagusss 2023-12-26 16:03:46 +08:00 暴露 http 接口不行么 |
4 Haku OP 我补充一下,因为上头有要求不开端口(否则会涉及大量的安全策略啥的问题),所以才无奈用的 exe 打包。正常来说跨语言第一反应肯定是走网络通信啥的, |
6 Ayanokouji 2023-12-26 16:10:56 +08:00 graalvm 试试,虽然我没用过 |
7 nagisaushio 2023-12-26 16:11:06 +08:00 via Android 走 unix file socket 也不行么 |
8 potatowish 2023-12-26 16:12:55 +08:00 via iPhone python 轮训数据库、队列,看是否有请求过来,有就处理; java 这边需要请求时就写入到数据库、队列,然后轮训获取响应…… |
10 Leon6868 2023-12-26 16:15:58 +08:00 可以看看 RPC 相关的内容 |
11 NULL2020 2023-12-26 16:16:09 +08:00 关注下,我司最近也要搞类似的方案 JNI-CPython-Python 这个方案大概是怎样,op 能否细说一下 |
12 lingeo 2023-12-26 16:16:23 +08:00 简单一点就是 web server ,优雅点就 grpc 。 |
13 Haku OP @Ayanokouji 我看看,这个看介绍说不定可以哦 |
14 Haku OP @NULL2020 如果你的 Python 不涉及第三方库或者你第三方库很简单(没有套娃似的依赖下去),那么你可以把你的 Python 代码通过 c 拓展模块编译成 so 文件,从而可以被 c 调用,而 Java 有 JNI 可以支持你通过 JAVA 来调用 c ,CPython 则负责编写 c 到 python 中间,你要暴露哪些方法出来。这样一来就可以直接由 Java 来调用 python 了。 具体的可以网上搜一下,应该资料也不算少。 而且这种方案一般也比网络方案要快一些,少了很多网络上的开销。但是我找不到第三方依赖的解决办法目前没法用。 |
15 nagisaushio 2023-12-26 16:25:56 +08:00 via Android 楼主先明确,是 不准 java 和 python 分开多个进程,还是只是不准经 tcp 通信? |
16 Haku OP @Leon6868 我们知道不会暴露到网络上,但是领导不知道,也不可能因为我们就改了安全策略。这个不是技术问题。实在是没法解决。┑( ̄Д  ̄)┍ |
17 Haku OP @nagisaushio 可以分进程,但是不分更好。网络通信是禁止的。 |
18 lsk569937453 2023-12-26 16:29:08 +08:00 @Haku 笑死,最后 java 调用完 python ,不还是暴漏 http 接口出去,只不过这个 http 是用 java 实现的??? |
19 nagisaushio 2023-12-26 16:29:09 +08:00 via Android @Haku 走 unix socket 也不行吗 |
21 Haku OP 对了还有个要求,不准直接带来或者改变服务器上的 python 环境。这个也是个坑点,导致我们也没法直接部署 python 代码而使用了 exe 让它可以脱离环境使用。 |
22 vicalloy 2023-12-26 16:31:39 +08:00 进程间通信总共也就这么几种方法。要不你们用共享内存吧。 |
23 lujiaxing 2023-12-26 16:31:52 +08:00 啥? 这算啥问题, 调 py 脚本难道不就是命令行不就完了么? |
24 Haku OP @lsk569937453 差不多是这样的,很离谱但是就是如此。 |
25 yushenglin 2023-12-26 16:33:01 +08:00 有任务队列么,封装一个订阅任务区处理 |
26 sujin190 2023-12-26 16:33:39 +08:00 @Haku #17 不可以开端口,难道也不可以开 pipe 么?还有 IPC 通信共享内存什么的吧,也没说一定要使用网络才能搞 RPC ,windows 还有更变态的直接用进程 ID 远程写进程内存然后通过内核信号量通知进程执行远程调用的 |
27 Haku OP @nagisaushio 这个我不太熟悉,我看看哈 |
28 Ayanokouji 2023-12-26 16:34:27 +08:00 容器也不行吗 |
29 nagisaushio 2023-12-26 16:35:41 +08:00 via Android @Haku "不准直接带来 python 环境"什么意思,我把依赖库打包成 zip 算吗? |
30 Haku OP |
31 Haku OP @nagisaushio 不解压就不算,解压哪怕用了虚拟环境也不行。 |
32 Haku OP @yushenglin 这个其实也算可以,不过被使用方否决了, @Ayanokouji 我记得和容器通信需要搞端口映射吧,因为最终还是要给 java 进程用的,java 进程不是我们写的,所以这个也不让用。 |
33 thinkershare 2023-12-26 16:43:09 +08:00 每个操作系统都有自己原生的多进程通讯模式,将你的 java/python 搞成多进程架构就行,Java 这边做主进程,负责管理和分发任务给 python 这边。python 是一定需要虚拟机的,不用虚拟机的 python 基本上啥也干不了,没几个库兼容,所以就将环境全部打包进入好了。 |
34 Ayanokouji 2023-12-26 16:43:39 +08:00 @Haku java 不是你们写的,就难办了,graalvm 估计调用方也不会用,还要安装新的 jdk 环境,按这描述只能进程间通信了吧 |
35 Ayanokouji 2023-12-26 16:48:53 +08:00 @Haku 我说的容器,当成 k8s 里边的 pod 理解,把 java 和 python 放到一个 pod 里边,docker 的话就是一个 compose ,设置下网络策略。在一个 pod 里边用 http 访问。不过按你这描述,容器应该也不会让你们用。 |
36 Haku OP @Ayanokouji 理解了。这样确实不行,java 那边不会挪窝的,我们这边最多就是提供点 jar 包做层封装让他们不直接接触 python 这边的东西。 |
37 NessajCN 2023-12-26 16:56:50 +08:00 你们编的啥安全策略还禁 localhost 访问的?需要特意改安全策略才允许 localhost 端口访问? |
38 Haku OP @NessajCN 是你可以访问,但是你访问前要给安全过一堆检查,还要写申请,开策略。是“非技术”方面的禁止而非“技术”方面的。但是你不涉及任何网络方面的东西的话,以上冗杂的流程就没了,而目前就是希望别走这个流程。 |
39 mightybruce 2023-12-26 17:02:58 +08:00 那么多 IPC 的通信方式, 你选一种就行。 简单点就是 unix domain socket, 复杂点搞共享内存、POSIX 消息队列。像这种通信有很多开发库都封装了,比如 zeromq , 自己多试试吧。 |
40 hellomsg 2023-12-26 17:09:38 +08:00 给 zfu 外包吗?这么奇葩 |
41 NessajCN 2023-12-26 17:14:24 +08:00 @Haku 我觉着要不你还是想办法换个不那么 sb 的领导比较可行 非技术障碍最好也用非技术手段扫除,找找他有没有财务漏洞或者外面是不是养了个三儿啥的 |
43 ychost 2023-12-26 17:22:33 +08:00 进程间通信就行了,这样不会暴露网络 |
44 yazinnnn0 2023-12-26 17:27:54 +08:00 python 监听 domain socket, 开个 web server, 不算网络服务 |
45 tomczhen 2023-12-26 17:36:43 +08:00 via Android 典型的没困难创造困难。就算有网友给指方向,非常规方案落地也有一堆坑等着踩。 |
47 Masoud2023 2023-12-26 17:49:18 +08:00 直接告诉老板不做 RPC 的话做不了,甭管 unix socket 还是 TCP ,至少你得沾一个,否则甭想。 |
48 Alias4ck 2023-12-26 18:08:55 +08:00 直接用 java 重写你们的的 python 项目吧 我觉得很符合你们的想法 |
49 XSDo 2023-12-26 18:16:06 +08:00 人为的设置那么多困难,我觉得还可以加更多困难下去,让这个功能实现起来更有挑战 |
50 penguinWWY 2023-12-26 18:23:47 +08:00 通过 pybind11 用 c++包一个 exe 出来,静态链接完整的 libpython ,所有依赖打成 zip 包直接通过 c 接口 import 进来 更新依赖的话就重新发个 zip 过去 |
51 xuelu520 2023-12-26 18:26:57 +08:00 grpc ,要么内网的 http 接口,再不然就 50 楼说的那种 |
52 bringyou 2023-12-26 18:28:37 +08:00 实在不行就把 python 都打包到 docker 镜像里,跑镜像就不算改变服务器 python 环境了? |
54 hertzry 2023-12-26 19:44:25 +08:00 第三方 package 也都是下载后使用的。譬如 Conda ,你可以找到那个 package 的路径,把它复制到你项目的同一个目录然后 import 。不出意外是可以正常运行的,那么此时相当于第三方 package 是你手动写的,这样打包试一下呢? |
55 nightwitch 2023-12-26 19:45:44 +08:00 走 unix domain socket 呗,进程间通信中比较好用的了。 shared memory 啥的,两边语言都不是 native 语言,操作内存费老大劲 |
57 reeco 2023-12-26 21:22:48 +08:00 python 也是 binding 到 c++,直接用 java binding 到 c++不就好了吗,一个容器搞定。 |
58 LoNeZ 2023-12-26 21:34:03 +08:00 grpc 通信...你这种方式只会增加复杂度... |
59 lujiaxing 2023-12-27 00:44:15 +08:00 @Haku 那就装一个呀~ 而且现代 Linux 操作系统一般都是自带 Python 环境的... 咋会出现缺 Python 环境的神奇现象 |
61 Haku OP @Alias4ck 这个倒是考虑过,但是 java 的效率太低了,处理起来时间上差不多是 python 的 20 多倍,已经到了无法接受的程度了。 |
62 MonTubasa 2023-12-27 10:22:52 +08:00 不知道是不是 linux 机器,如果是在同一台 linux 机器的话,是否可以考虑通过/dev/shm 来进行数据交换。不太确定会不会有内存泄漏或者其他安全问题,看你们考虑考虑。 |
63 cheng6563 2023-12-27 11:04:21 +08:00 不开端口,那就开 unix socket 呗 |
64 leejoker 2023-12-27 11:06:20 +08:00 可以试试 deeplearning4j 里边的 python4j ,走的是 javacpp 调用 cpython |
65 leejoker 2023-12-27 11:07:21 +08:00 之前做过一些图像检测算法的继承,性能还行 |
66 leejoker 2023-12-27 11:07:35 +08:00 集成 |
67 huangzhe8263 2023-12-27 11:38:06 +08:00 cx-freeze 把 python 和 python 依赖全部打包,通过一个 executable 文件执行,然后直接 java 执行本地命令? |
68 ShadowPower 2023-12-27 12:24:50 +08:00 如果 Python 和 Java 都在同一台机器上 用命名管道来传数据就好了 |
69 CaptainD 2023-12-27 13:33:15 +08:00 我们公司类似的需求是用的消息队列,Java 端将请求放入队列,Python 程序读取队列内容执行 LLM 相关操作,生成结果插入数据库和队列,Java 端再读取,因为 Python 端工作时间会非常长,一般的连接不能满足要求 |
70 summerLast 2023-12-27 14:27:14 +08:00 python java 打包成一个 docker 镜像,然后内部网络通讯,对外控制端口暴露 |
71 summerLast 2023-12-27 14:28:26 +08:00 mq? |
72 Anonono 2023-12-27 14:39:39 +08:00 看起来是用 docker 更合理些,但是看 OP 描述估计也够呛 |
73 buliugu 2023-12-27 15:03:28 +08:00 改成 docker-compose ,容器间调用,不暴露端口 |
74 maybedk 2023-12-27 15:25:37 +08:00 python 有 env 啊,你的三方库全装在 env 里,只要你的 python 版本和目标环境的 python 版本一致就行。运行的时候 source 到虚拟环境然后执行 py 文件就能跑起来。 |
75 chaoschick 2023-12-28 08:34:37 +08:00 via Android 将 Python 项目打包成一个动态链接库( DLL )可以通过使用 py2dll 或者 PyInstaller 配合一些手动操作来完成。 首先,确保 Python 项目中的所有依赖项都已经被安装并且可以在项目中导入。 接下来,您可以使用 PyInstaller 将 Python 脚本打包成单一的可执行文件,PyInstaller 有一个选项--onefile ,能够将所有的依赖项打包到一个文件中,包括 Python 解释器和所有库文件。 PyInstaller 不能直接生成 DLL ,但您可以首先生成一个 EXE ,然后将其转换为 DLL 。对于转换,这通常需要手动操作以及对 C/C++的理解,因为您可能需要编写一些额外的代码来导出 DLL 的符号。 这里是一个高级概览的步骤: 1. 使用 PyInstaller 将 Python 项目打包成 EXE: pyinstaller --onefile your_script.py 使用--onefile 选项打包您的脚本及其所有依赖项。 2. 创建 C/C++的包装器代码,这代码会作为 DLL 对外提供接口,并内部调用 Python 解释器执行您的 Python 代码。 3. 编译这个 C/C++代码到 DLL ,链接上一步创建的可执行文件包含的静态库或者动态库。 4. 确保 Python 运行环境(如 Python 解释器和所需的库文件)对 DLL 是可见的,可以通过添加环境变量或者将它们放置在预定的目录。 注意:这是一个比较复杂的过程,需要一定的编程和操作系统内部工作机制的知识,如果您不熟悉这些概念,那么建议寻求更专业的帮助或者使用其他解决方案。 此外,您还可以考虑使用 Cython 来编译 Python 代码为 C 代码,然后生成 DLL ,但这通常需要您的代码适应 Cython 的一些限制。 对于静态打包所有 Python 依赖到一个 DLL 文件,目前没有一个标准的解决方案,通常需要一些定制和手工操作。可以考虑打包你的 Python 环境和脚本到一个虚拟环境中,然后将整个虚拟环境连同生成的 DLL 一起分发。 |
76 nielinjie 2023-12-28 15:17:27 +08:00 最好把 python 和 java 安排在不同进程中。这样既比较好办,也比较容易向前兼容( Forwards Compatibility )。进程间通信(包括控制)的手段就很多了,文件系统、数据库、端口等等。 |
77 HashV2 2024-01-02 13:56:00 +08:00 我这边自己项目在用的方案是 docker dockerfile 基于 python 3.10.12 Cython 把代码打包成 so ,同时 pip install -r requirements.txt 然后不写 cmd ,run container 的时候需要执行什么命令就打什么命令 后面就通过 docker 正常使用了 不过我不知道编译之后怎么调用,所以我是保留了入口文件没有编译的,目前运行良好 |