Java调用python脚本,BufferedReader的readline函数无任何输出结果,进程长时间卡住
最近在做项目时,需要用到Java调用python文件并读取运行结果。一般Java调用简单的Python文件(不包含第三方库的)是没有任何问题的,但是我需要用到tensorflow、keras、numpy等第三方库,所以遇到了很多麻烦,经过各种百度查找,最终解决了问题,在这里做一个总结归纳。
问题1 Java调用python返回值一直为null
这个问题是我没有创建虚拟环境造成的,因为自己电脑上用的一直是Anaconda安装时自带的python,没有创建自己的虚拟环境,因此在Java中调用python文件时,就会找不到各种第三方库的问题。
问题2 BufferedReader的readline函数无任何输出结果,进程长时间卡住
这个问题我也找了很多方法才解决,产生这个问题的主要原因是:
命令在运行的过程中会向标准输出或者标准错误输出写出数据,但JVM又没有去读,导致缓冲区满,进而导致进程阻塞。因为我的python文件调用的tensorflow,他会输出一堆警告信息,这些警告信息属于错误流(ErrorStream),如果我们没有及时处理,就会导致缓冲区占满,从而导致进程阻塞。
Process.getInputStream()和Process.getErrorStream()分别返回Process的标准输出流和错误流,两个流如果处理不当,其缓冲区不能被及时清除而被塞满,则进程被阻塞,即使调用Process.destory()也未必能销毁被阻塞的子进程。
这个问题的解决的方法比较简单,既然问题是缓冲区满之后没有及时清理,那么只要在Java代码里去读一下数据,保证缓冲区不会满即可.
具体代码如下:
public static void main(String[] args) {
try{
System.out.println("start");
//一定要用虚拟环境下的python路径
String[] args1=new String[]{"D:\\SoftWare\\Anaconda\\envs\\jst\\python.exe","F:\\Python_Project\\test.py"};
Process pr = Runtime.getRuntime().exec(args1);
// 防止缓冲区满, 导致卡住
new Thread() {
@Override
public void run() {
super.run();
String line;
try {
BufferedReader stderr = new BufferedReader(new InputStreamReader(pr.getErrorStream(),"GBK"));
while ((line = stderr.readLine()) != null) {
System.out.println("stderr:" + line);
}
}
catch (Exception e) {
}
}
}.start();
System.out.println("==============打印结果==============");
new Thread() {
@Override
public void run() {
super.run();
String line;
try {
BufferedReader stdout = new BufferedReader(new InputStreamReader(pr.getInputStream(),"GBK"));
while ((line = stdout.readLine()) != null) {
System.out.println("stdout:" + line);
}
}
catch (Exception e) {
}
}
}.start();
int exitVal = pr.waitFor();
if (0 != exitVal) {
System.out.println("执行脚本失败");
}
System.out.println("执行脚本成功");
} catch (Exception e){
e.printStackTrace();
}
}