V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Haku
V2EX  ›  Python

请问下 Java 如何调用含有第三方依赖的 Python 项目

  •  1
     
  •   Haku · 2023-12-26 15:58:22 +08:00 · 6280 次点击
    这是一个创建于 367 天前的主题,其中的信息可能已经有所发展或是发生改变。

    公司想搞 AI 相关的,但老企业用的全是 java ,结果就是要用 java 调 python 。

    目前只能搞成 java 调 python 打包的 exe 。

    也想过用 JNI-CPython-Python 的思路,但是解决不了 python 依赖大量第三方库的问题,没法把 python 代码包括第三方依赖一起给打包成 so 文件。

    想问问有没有技术大佬有啥解决思路或者方案。

    77 条回复    2024-01-02 13:56:00 +08:00
    Nooooobycat
        1
    Nooooobycat  
       2023-12-26 16:01:30 +08:00   ❤️ 2
    Python 这边集成一个 web 框架,HTTP 请求进来的时候调用 AI 相关的逻辑。 这样别说用 Java ,bash shell 调用都行
    Haku
        2
    Haku  
    OP
       2023-12-26 16:03:18 +08:00
    @Nooooobycat 这种方案肯定是可行的,但是公司这边这次不让,这次需求上就是不准开端口。
    vagusss
        3
    vagusss  
       2023-12-26 16:03:46 +08:00
    暴露 http 接口不行么
    Haku
        4
    Haku  
    OP
       2023-12-26 16:04:51 +08:00
    我补充一下,因为上头有要求不开端口(否则会涉及大量的安全策略啥的问题),所以才无奈用的 exe 打包。正常来说跨语言第一反应肯定是走网络通信啥的,
    Haku
        5
    Haku  
    OP
       2023-12-26 16:06:10 +08:00
    @vagusss 上头不让干,大头兵只能无奈执行。
    Ayanokouji
        6
    Ayanokouji  
       2023-12-26 16:10:56 +08:00   ❤️ 1
    graalvm 试试,虽然我没用过
    nagisaushio
        7
    nagisaushio  
       2023-12-26 16:11:06 +08:00 via Android   ❤️ 1
    走 unix file socket 也不行么
    potatowish
        8
    potatowish  
       2023-12-26 16:12:55 +08:00 via iPhone
    python 轮训数据库、队列,看是否有请求过来,有就处理; java 这边需要请求时就写入到数据库、队列,然后轮训获取响应……
    Leon6868
        9
    Leon6868  
       2023-12-26 16:14:36 +08:00
    @Haku 监听 127.0.0.1 上的端口,不会暴露到网络
    Leon6868
        10
    Leon6868  
       2023-12-26 16:15:58 +08:00
    可以看看 RPC 相关的内容
    NULL2020
        11
    NULL2020  
       2023-12-26 16:16:09 +08:00
    关注下,我司最近也要搞类似的方案

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

    dockerfile 基于 python 3.10.12 Cython 把代码打包成 so ,同时 pip install -r requirements.txt

    然后不写 cmd ,run container 的时候需要执行什么命令就打什么命令

    后面就通过 docker 正常使用了

    不过我不知道编译之后怎么调用,所以我是保留了入口文件没有编译的,目前运行良好
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4946 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 09:42 · PVG 17:42 · LAX 01:42 · JFK 04:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.