使用的方法是Runtime.getRuntime().exec(命令行),下面是项目里用来生成命令行的方法
// 生成脚本命令
private String buildModelCMD() {
// 业务代码,略过
// conda环境名称 + python程序路径 + 各种参数
String cmd = String.format("CMD /C activate %s && python -u %s %s %s",/*参数已省略*/);
// 替换转义字符
cmd = cmd.replaceAll("\\\\", "/");
cmd = cmd.replaceAll("/r", "\\\\r");
cmd = cmd.replaceAll("/n", "\\\\n");
cmd = cmd.replaceAll("/c", "\\\\c");
return cmd;
}
下面是模型运行工具,使用function回调处理python实时打印的信息,modelruninfo是和python约定的输出格式
/**
* python模型运行工具
*/
public class PythonRunnerUtil {
/**
* 运行python命令
*
* @param globalScript 命令行
* @param callback 回调函数,参数为ModelResult类型
* @param finalCallBack 最终的回调,参数1有问题 0正常
*/
public static void runPython(
String globalScript,
Function<Object, ModelRunInfo> callback,
Function<Object, Integer> finalCallBack
) {
try {
Process process = Runtime.getRuntime().exec(globalScript);
// 读取运行过程输出信息
Thread thread = printMessage(
process.getInputStream(),
process.getErrorStream(),
(Object result) -> {
callback.apply(result);
return result;
}
);
thread.join();
finalCallBack.apply(process.waitFor()); // 1有问题 0正常
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 运行python,打印运行状态
*
* @param out 输出流
* @param err 错误流
* @param callback 运行中的回调
* @return Thread
*/
private static Thread printMessage(
final InputStream out,
final InputStream err,
Function<Object, Object> callback
) {
Thread thread = new Thread(() -> {
Reader outReader = new InputStreamReader(out);
BufferedReader outBf = new BufferedReader(outReader);
Reader errReader = new InputStreamReader(err);
BufferedReader errBf = new BufferedReader(errReader);
String outLine, errLine = null;
ModelRunInfo modelRunInfo = null;
try {
while (
(outLine = outBf.readLine()) != null
||
(errLine = errBf.readLine()) != null
) {
System.out.println("python print outline >> " + outLine);
if (outLine != null) {
modelRunInfo = parsePrint(outLine);
}
if (errLine != null) {
modelRunInfo = new ModelRunInfo("error", -1, errLine);
}
if (modelRunInfo != null) {
// 运行中的回调
callback.apply(modelRunInfo);
}
}
outBf.close();
errBf.close();
} catch (IOException e) {
modelRunInfo = new ModelRunInfo("error", -1, e.toString());
callback.apply(modelRunInfo);
} finally {
try {
outBf.close();
errBf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
return thread;
}
/**
* 将python打印输出的信息过滤后存为ModelRunInfo格式
*
* @param out 输出的字符串
* @return ModelRunInfo
*/
private static ModelRunInfo parsePrint(String out) {
if (!out.startsWith("$JAVA$")) {
return null;
}
out = out.replaceAll("\\$JAVA\\$", "");
return JSON.parseObject(out, ModelRunInfo.class);
}
}
/**
* python运行的打印输出格式
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ModelRunInfo {
String status;
int progress;
String jsonPath;
// json输出文件里file和data的key
public static final String FILE_KEY = "file";
public static final String DATA_KEY = "data";
}
调用的示例
PythonRunnerUtil.runPython(cmd, (Object result) -> {
ModelRunInfo modelRunInfo = (ModelRunInfo) result;
log.info("model print >> " + modelRunInfo.toString());
if (modelRunInfo.getProgress() == 100 && !modelRunInfo.getStatus().equals("error")) {
// 具体业务
}
return (ModelRunInfo) result;
}, (Object finalResult) -> {
int res = (Integer) finalResult;
log.info("model end at >> " + DateTime.now().toString() + " with status " + res);
return res;
});
该博客介绍了如何在Java中通过Runtime.getRuntime().exec()方法执行Python脚本,并利用回调函数实时处理Python运行过程中的输出信息。内容包括构建命令行字符串,解析Python的打印输出,以及定义回调函数来处理模型运行状态。示例展示了如何在运行结束时进行最终回调,以判断运行是否成功。
4847

被折叠的 条评论
为什么被折叠?



