Java调用含第三方库Python脚本传递数据并返回计算结果

需求:最近在使用基于Java编写的Cloudsim 4.0云仿真平台进行虚拟机动态迁移实验,由于中间有需要用到深度强化学习算法,因此需要将集群的状态表示为二维数组,比如物理机的计算能力Mips,RAM,带宽等等。希望将这样的二维数组传入到带torch等第三方库的Python脚本进行深度强化学习训练,所以就有二维int数组的传入,和从Python计算后的结果返回读取这个需求

一、实现思路:将Java中的data结构化为字符串,以命令行参数的形式传入Python中

目前有几种Java调用Python的方法,不过能良好兼容Python第三方库的方法通常是使用

Process proc = Runtime.getRuntime().exec(args1); // 执行Python脚本并传参数

如果只是简单传入几个数字,或者几个URL,比如可直接写为

int num1 = 5;
int num2 = 10;
Process proc = Runtime.getRuntime().exec(args1, String.valueOf(num1), String.valueOf(num2));

而如果要传入多维数组且每次传递时数组的大小会变,比如

int[][] stateInt = new int[][]{{2500, 5, 2610, 2620, 2630, 2640, 2650, 2660},  // Mips
                               {870,  5, 4091, 4092, 4093, 4094, 4095, 4096}}; // RAM

则需要把要传入的多维数据,结构化为可分割的字符串,上述二维数组就可转变为如下字符串

"2500 5 2610 2620 2630 2640 2650 2660;870 5 4091 4092 4093 4094 4095 4096"

这样传入到Python中就可以根据;<空格>通过split()将二维数组恢复出来

二、Python实现代码

import sys
from selenium import webdriver
import torch


def policy(state):
    action = [2, 1, 0, 0]
    action[0] += state[0][1]
    return action

def str2int(stateStr):
    '''将完整字符串转换为二维数组'''
    stateList = []
    multiVimState = stateStr.split(';')
    for singleVimState in multiVimState:
        elements = singleVimState.split(' ')
        singleVimList = []
        for e in elements:
            singleVimList.append(int(e))
        stateList.append(singleVimList)
    return stateList

def int2str(actionIntArr):
    '''将形如[0,1,0,0,0]的int动作向量转化为01000字符串,方便Java处理'''
    actionStr = '';
    for e in actionIntArr:
        actionStr += str(e)
    return actionStr

if __name__ == '__main__':
    state = []
    stateStr = sys.argv[1];
    stateIntArr = str2int(stateStr)
    actionIntArr = policy(stateIntArr)
    actionStr = int2str(actionIntArr)
    # [2+5=7, 1, 0, 0] => 7100
    print(actionStr)

三、Java实现代码

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class testPython {
    /**
     * 将整型state数组转换为带分隔符的字符串,方便以命令方式传递给Python文件以进行计算
     * @param stateInt 当前虚机 + 所有主机状态向量
     * @return
     */
    public static String state2str(int[][] stateInt){
        String stateStr = "";
        for (int i = 0; i < stateInt.length; i++) {
            for (int j = 0; j < stateInt[0].length; j++) {
                if (j == 0)  stateStr += String.valueOf(stateInt[i][j]);
                else         stateStr += " " + String.valueOf(stateInt[i][j]);
            }
            if (i != stateInt.length - 1)  stateStr += ";";
        }
        return stateStr;
    }

    public static void main(String[] args) throws Exception {
        // Python文件地址(Linux)
        String pyPath = "/XXXX/XXXX.py";

        int[][] stateInt = new int[][]{{2500, 5, 2610, 2620, 2630, 2640, 2650, 2660},  // Mips
                                       {870,  5, 4091, 4092, 4093, 4094, 4095, 4096}}; // RAM
        // 将整型state数组转换为带分隔符的字符串,方便以命令方式传递给Python文件以进行计算
        String stateStr = state2str(stateInt);
        String[] args1 = new String[] {"python", pyPath, stateStr};
        // 执行Python文件,并传入参数
        Process proc = Runtime.getRuntime().exec(args1);
        // 获取Python输出字符串作为输入流被Java读取
        BufferedReader in = new BufferedReader(new InputStreamReader( proc.getInputStream() ));
        String actionStr = in.readLine();
        if (actionStr != null)
            System.out.println(actionStr);
            
        in.close();
        proc.waitFor();

        // 将获取的字符串分割为字符串数组,然后逐个元素转换为int并求和
        String nums[] = actionStr.split("");
        int sum = 0;
        for (int i = 0; i < nums.length; i++)
            sum += Integer.valueOf(nums[i]);
        System.out.println("求和为:" + sum);
    }
}

运行Java代码后得到如下结果

在这里插入图片描述

参考文献

[1] bethansy.java调用python脚本并向python脚本传递参数
[2] Java调用Python程序方法总结
[3] java调用python的几种用法(看这篇就够了)

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
您可以使用`ProcessBuilder`类来调用Python脚本并传递参数。首先,确保您已经安装了`python`命令。然后,可以使用以下Java代码来调用Python脚本并传递参数: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class PythonCaller { public static void main(String[] args) { try { // 构建命令和参数列表 String pythonScriptPath = "/path/to/python_script.py"; // 替换为您的Python脚本路径 String[] cmd = new String[3]; cmd[0] = "python"; cmd[1] = pythonScriptPath; cmd[2] = "parameter1"; // 替换为您要传递的参数 // 创建进程并执行命令 ProcessBuilder pb = new ProcessBuilder(cmd); Process process = pb.start(); // 获取命令输出 InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 等待命令执行完成 int exitCode = process.waitFor(); System.out.println("Exited with error code : " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } ``` 请注意,您需要将`/path/to/python_script.py`替换为您的Python脚本的实际路径,并在`cmd`数组中添加要传递的参数。 这段代码将启动一个新的进程来执行Python脚本,并将输出打印到标准输出。您可以根据需要修改代码来处理输出或错误信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SL_World

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值