在关闭输入流之前,java无法读取python进程的输出

时间:2018-03-28 14:08:54

标签: java python multithreading io subprocess

在为子流程运行创建管理器时遇到一些问题。这些子进程就是python脚本。我需要在不同的线程中编写/读取/包装进程的错误。我创建了一些简单的测试:

test.py

import sys

if __name__ == "__main__":
 print ("START TEST SCRIPT")
 print ("SOME STRING")
 for line in sys.stdin:
  print ("DEBUG>>> "+ line)

创建一个simpe java测试类:

public class Test {

    public static void main(String[] args) {
        ProcessBuilder builder = new ProcessBuilder("python", "test.py");
        builder.environment().put("PYTHONIOENCODING", "UTF-8");
        builder.directory(new File("./test/external_processes/python"));
        try {
            Process environmentProcess = builder.start();
            InputStream out = environmentProcess.getInputStream();
            InputStream err = environmentProcess.getErrorStream();
            OutputStream in = environmentProcess.getOutputStream();

            Thread t1 = new Thread(() -> {
                OutputStreamWriter writer = new OutputStreamWriter(in);
                try {
                    writer.write("new string");
                    writer.flush();
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            Thread t2 = new Thread(() -> {
                byte[] buffer = new byte[4096];
                int count;
                try {
                    while ((count = out.read(buffer)) >= 0) {
                        System.out.println("[TASK STREAMER] " + new String(buffer, 0, count));
                    }
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            Thread t3 = new Thread(() -> {
                byte[] rbuffer = new byte[4096];
                int rcount;
                try {
                    int rno = err.available();
                    while ((rcount = err.read(rbuffer)) >= 0) {
                        System.out.println("[TASK STREAMER ERR] " + rno + " :: " + new String(rbuffer, 0, rcount));
                    }
                    err.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            t1.start();
            t2.start();
            t3.start();

            t1.join();
            t2.join();
            t3.join();

            environmentProcess.waitFor();
            System.out.println("ok!");

            environmentProcess.getInputStream().close();
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

一切都很顺利

Connected to the target VM, address: '127.0.0.1:50726', transport: 'socket'
[TASK STREAMER] START TEST SCRIPT
SOME STRING
DEBUG>>> new string

Disconnected from the target VM, address: '127.0.0.1:50726', transport: 'socket'
ok!

Process finished with exit code 0

直到我决定不写任何输出,所以我删除了线程t1。在那之后,一个cant从python到达前两行(" START TEST SCRIPT"," START TEST SCRIPT")并且执行被卡住了。

因此,如果代码如下所示:

import java.io.*;

public class Test {

    public static void main(String[] args) {
        ProcessBuilder builder = new ProcessBuilder("python", "test.py");
        builder.environment().put("PYTHONIOENCODING", "UTF-8");
        builder.directory(new File("./test/external_processes/python"));
        try {
            Process environmentProcess = builder.start();
            InputStream out = environmentProcess.getInputStream();
            InputStream err = environmentProcess.getErrorStream();

            Thread t2 = new Thread(() -> {
                byte[] buffer = new byte[4096];
                int count;
                try {
                    while ((count = out.read(buffer)) >= 0) {
                        System.out.println("[TASK STREAMER] " + new String(buffer, 0, count));
                    }
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            Thread t3 = new Thread(() -> {
                byte[] rbuffer = new byte[4096];
                int rcount;
                try {
                    int rno = err.available();
                    while ((rcount = err.read(rbuffer)) >= 0) {
                        System.out.println("[TASK STREAMER ERR] " + rno + " :: " + new String(rbuffer, 0, rcount));
                    }
                    err.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            t2.start();
            t3.start();

            t2.join();
            t3.join();

            environmentProcess.waitFor();
            System.out.println("ok!");

            environmentProcess.getInputStream().close();
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我会达到这个目的:

Connected to the target VM, address: '127.0.0.1:50726', transport: 'socket'

我理解这个过程因为python等待输入而不会停止,但我至少期待两个第一个字符串(" START TEST SCRIPT"," START TEST SCRIPT")

但是如果我先关闭输出流,我会达到这个字符串。任何人都可以帮助我理解这种情况,以及如果内部有以太输入读取和写入输出,如何到达子进程输出?

P.S。对不起我的俄语语法。

2 个答案:

答案 0 :(得分:0)

在你的python代码中,你需要刷新打印输出。

import sys

if __name__ == "__main__":
 print ("START TEST SCRIPT", flush=True)
 print ("SOME STRING", flush=True)
 for line in sys.stdin:
  print ("DEBUG>>> "+ line)

答案 1 :(得分:0)

如果它对任何人都有用,我会在不改变客户端python代码的情况下找到另一种方法。

A已向构建者添加了一些额外的环境:

undefined method create_record for #<ForgotPassword:0x000000000622bc98>