JAVA的Runtime.getRuntime().exec阻塞问题

       最近在写毕业设计,有人脸识别的需求,客户端方面用python,TensorFlow,facenet,opencv可以搞定。但是在后端(用java写的)我想直接网页上传图片到后台,然后服务器去算特征并写到数据库里面。然鹅,没有找到facenet的java版,再加上本人比较懒,不想用java照着facenet的python代码,重新实现一遍。就想用客户端里面已经写过的获取特征的代码,直接复制一份python的代码,专门用来获取特征。用java来跑python。

       问题提出

        最开始百度的jython,说是java版的python,日常说的python都是指的cpython,C语言编的。当然也有java版的就是jython了。我也试了个小demo,但是我又想到Tensorflow,numpy啥的一大堆复杂的东西要引入,就听麻烦,果断放弃这条路。

public class Hello {
    public static void main(String[] args) throws Exception{
        Properties props = new Properties();
        props.put("python.import.site","false");
        Properties prepros = System.getProperties();
        PythonInterpreter.initialize(prepros,props,new String[0]);
        PythonInterpreter interpreter = new PythonInterpreter();
        interpreter.exec("print('Hello')");
    }
}

然后找的就是用java在控制台中利用cmd去跑python,意思就是让java开一个进程,用命令行去运行python,将结果用数据流得到。当然很简单就是Runtime.getRuntime().exec(command)嘛,然而初次接触这个方法的我天真的以为一切会很顺利。我试验的其他python代码都可以,就是我写的识别特征的那个代码不行,报错也没有,程序就卡在那里。代码单独在电脑的控制台运行也是调试通过了的,得到了特征数据。当看到这个博客http://blog.sina.com.cn/s/blog_500d9d15010083oo.htmlhttps://blog.csdn.net/u010414589/article/details/77725896?utm_source=blogxgwz1的时候。发现了实际问题,java程序给进程的输出流分配的缓冲区是很小的,有时候当进程输出信息很大的时候回导致缓冲区被填满,如果不及时处理程序会阻塞

        解决过程

        最开始肯定是先试试这个博文http://blog.sina.com.cn/s/blog_500d9d15010083oo.html的方法了,他的想法是可行的,运行进程,间隔500毫秒进行读取那个数据流。然而并不能解决我的问题,我想既然会因为缓冲区不够而阻塞,会不会内存分配的问题,导致挂起。再次运行,调出任务管理器,看到这个调用的python内存在疯涨,CPU占有率也会来回浮动。直到内存到了1163.9MB的时候,占有率降到0%,内存停住不再动。肯定是被挂起了,输出也没有。

        问题解决

        最终还是看的知乎上https://zhuanlan.zhihu.com/p/25249051这篇文章,虽然是StackOverflow上的截图,确实问题得到了解决。

import org.python.util.PythonInterpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

/*
    Create by:fshao
    Date:2020/3/14
    param:
    describe:
    qq:1378501215
*/
public class Hello {
    public static void main(String[] args) throws Exception{
        ProcessBuilder pb = new ProcessBuilder("python","F:\\BlackTechnology\\MTCNN_tf\\比对\\facenet-master\\src\\untitled1.py");
        pb.redirectErrorStream(true); //将error数据流重定向到标准输出stdout
        Process p = pb.start(); //开启进程
        new Thread(new ProcessTestRunnable(p)).start(); //开启新的线程接受数据流的输入
        p.waitFor();
    }

}

class ProcessTestRunnable implements Runnable{
    Process p;
    BufferedReader br;
    ProcessTestRunnable(Process p){
        this.p = p;
    }

    @Override
    public void run() {
        try{
            InputStreamReader isr = new InputStreamReader(p.getInputStream(),"GBK");
            br = new BufferedReader(isr);
            String line = null;
            while((line = br.readLine()) != null){
                System.out.println(line);
            }
        }catch (IOException ex){
            ex.printStackTrace();
        }

    }
}

使用方法:

ProcessBuilder(List<String> command)

Process的方法

1、destroy()       杀死这个子进程(是否强行终止取决于它的实现)

2、destroyForcibly()          强行终止子进程

3、isAlive()                        查看子进程是否活着

4、exitValue()       得到进程运行结束后的返回状态,0为正常停止

5、waitFor()       得到进程运行结束后的返回状态,如果进程未运行完毕则等待知道执行完毕

6、getInputStream()     得到进程的标准输出信息流

7、getErrorStream()     得到进程的错误输出信息流

8、getOutputStream()     得到进程的输入流

之前学的都是创建线程,今天用到了java创建子进程,觉得挺有意思的,记录一下。如有错误,欢迎补充指正。。。^_^!

        

猜你喜欢

转载自blog.csdn.net/qq_36571422/article/details/104880004
今日推荐