公司想搞 AI 相关的,但老企业用的全是 java ,结果就是要用 java 调 python 。
目前只能搞成 java 调 python 打包的 exe 。
也想过用 JNI-CPython-Python 的思路,但是解决不了 python 依赖大量第三方库的问题,没法把 python 代码包括第三方依赖一起给打包成 so 文件。
想问问有没有技术大佬有啥解决思路或者方案。
1
Nooooobycat 2023-12-26 16:01:30 +08:00 2
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 1
graalvm 试试,虽然我没用过
|
7
nagisaushio 2023-12-26 16:11:06 +08:00 via Android 1
走 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 1
@Haku 走 unix socket 也不行吗
|
21
Haku OP 对了还有个要求,不准直接带来或者改变服务器上的 python 环境。这个也是个坑点,导致我们也没法直接部署 python 代码而使用了 exe 让它可以脱离环境使用。
|
22
vicalloy 2023-12-26 16:31:39 +08:00 2
进程间通信总共也就这么几种方法。要不你们用共享内存吧。
|
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 1
每个操作系统都有自己原生的多进程通讯模式,将你的 java/python 搞成多进程架构就行,Java 这边做主进程,负责管理和分发任务给 python 这边。python 是一定需要虚拟机的,不用虚拟机的 python 基本上啥也干不了,没几个库兼容,所以就将环境全部打包进入好了。
|
34
Ayanokouji 2023-12-26 16:43:39 +08:00 1
@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 1
那么多 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 1
通过 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 环境了?
|
53
Belmode 2023-12-26 18:35:20 +08:00
@Haku "但是你访问前要给安全过一堆检查,还要写申请,开策略" 你这段,我是真的看不懂。跨网络环境,跨机器访问,确实可能需要申请权限,我本机访问本机 http 的 port ,连服务器的外部安全策略都不需要过,还要需要申请什么权限。。。
|
54
hertzry 2023-12-26 19:44:25 +08:00 1
第三方 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 1
可以试试 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 1
最好把 python 和 java 安排在不同进程中。这样既比较好办,也比较容易向前兼容( Forwards Compatibility )。进程间通信(包括控制)的手段就很多了,文件系统、数据库、端口等等。
|
77
HashV2 360 天前
我这边自己项目在用的方案是 docker
dockerfile 基于 python 3.10.12 Cython 把代码打包成 so ,同时 pip install -r requirements.txt 然后不写 cmd ,run container 的时候需要执行什么命令就打什么命令 后面就通过 docker 正常使用了 不过我不知道编译之后怎么调用,所以我是保留了入口文件没有编译的,目前运行良好 |