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 · 331 天前 · 5978 次点击
    这是一个创建于 331 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    后面就通过 docker 正常使用了

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