【问题标题】:java could not read output of python process until close the input streamjava在关闭输入流之前无法读取python进程的输出
【发布时间】:2018-09-07 06:33:26
【问题描述】:

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

test.py

import sys

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

并创建一个简单的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。之后,无法从 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”)。

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

附言对不起我的俄语语法。

【问题讨论】:

  • 显示发生错误行为之后的代码。
  • 已添加代码
  • 你的python版本是什么?
  • python 3.5.some
  • 让人们以他们想要的方式编写他们的第三方脚本很重要。

标签: java python multithreading io subprocess


【解决方案1】:

在您的 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)

【讨论】:

    【解决方案2】:

    如果它对任何人有用,我已经找到了一种无需更改客户端 python 代码的替代方法。

    A 为 builder 添加了一些额外的环境:

    builder.environment().put("PYTHONUNBUFFERED","TRUE");
    

    【讨论】:

      猜你喜欢
      • 2015-12-23
      • 1970-01-01
      • 2015-06-18
      • 2021-03-09
      • 2012-03-21
      • 2015-02-10
      • 2013-09-19
      • 1970-01-01
      • 2011-09-04
      相关资源
      最近更新 更多