将 InputStream 复制到 OutputStream 会停止,除非我也写入 System.out
Copying InputStream to OutputStream halts unless I also write to System.out
所以,我有一个 Python 进程,我是 运行 来自 Java。我正在尝试将其输出复制到 OutputStream。进程运行正常;但是,每当我尝试将 Process#getInputStream()
和 Process#getErrorStream()
复制到 OutputStream 时,程序就会挂起。
为了调试它,我添加了一个打印语句来在每次迭代时输出缓冲区,如下所示:
public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[4096];
int n = 0;
while ((n = in.read(buffer)) != -1) {
// I have no clue why, but this only works if I print the output to sysdout
System.out.println(new String(buffer));
out.write(buffer, 0, n);
}
}
出于某种奇怪的原因,这样做使一切都按预期进行。尝试刷新 OutputStream,刷新 System.out,或将空字符打印到标准输出,或事件打印普通 byte[] buffer
都不起作用,只有我上面的方法有效。
发生这种情况的代码是怎么回事?
编辑:显示用法
public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {
int status = -1;
Logger logger = Util.getOutputStreamLogger(moduleOut);
logger.info("Starting module {}", getModuleName());
ProcessBuilder exec = new ProcessBuilder();
exec.directory(getWorkingDirectory());
if (configureEnvironment(exec.environment(), moduleOut)) {
List<String> command = getExecutable();
command.addAll(arguments);
exec.command(command);
LOGGER.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
LOGGER.info("In: {}", getWorkingDirectory());
LOGGER.info("Executing: {}", StringUtils.join(command, " "));
Process proc = exec.start();
LOGGER.info("Copying input stream");
copy(proc.getInputStream(), moduleOut);
try {
logger.info("Waiting for process");
status = proc.waitFor();
if (status != 0) {
logger.error("The process failed with the following error: ");
copy(proc.getErrorStream(), moduleOut);
}
logger.info("The process finished with exit code: {}", status);
} catch (InterruptedException e) {
LOGGER.warn("The thread was interrupted", e);
Thread.currentThread().interrupt();
}
} else {
logger.info("Module configuration failed");
}
Util.detachOutputStreamFromLogger(logger);
return status;
}
正如 EJP 所建议的那样,我通过执行程序将流的复制拆分为单独的线程,然后确保在生成的进程完成后关闭它们:
public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {
int status = -1;
Logger logger = Util.getOutputStreamLogger(moduleOut);
logger.info("Starting module {}", getModuleName());
ProcessBuilder exec = new ProcessBuilder();
exec.directory(getWorkingDirectory());
if (configureEnvironment(exec.environment(), moduleOut)) {
List<String> command = getExecutable();
command.addAll(arguments);
exec.command(command);
logger.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
logger.info("In: {}", getWorkingDirectory());
logger.info("Executing: {}", StringUtils.join(command, " "));
Process proc = exec.start();
try (InputStream procOut = proc.getInputStream(); InputStream procErrOut = proc.getErrorStream()) {
copy(procOut, moduleOut);
copy(procErrOut, moduleOut);
LOGGER.debug("Waiting for process to finish");
status = proc.waitFor();
LOGGER.debug("Closing streams");
procOut.close();
procErrOut.close();
logger.info("The process finished with exit code: {}", status);
} catch (InterruptedException e) {
LOGGER.warn("The thread was interrupted", e);
Thread.currentThread().interrupt();
}
} else {
logger.info("Module configuration failed");
}
Util.detachOutputStreamFromLogger(logger);
return status;
}
public void copy(final InputStream in, final OutputStream out) throws IOException {
executor.execute(() -> {
try {
byte[] buffer = new byte[4096];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
} catch (IOException e) {
LOGGER.error("Ya done goofed", e);
}
});
}
所以,我有一个 Python 进程,我是 运行 来自 Java。我正在尝试将其输出复制到 OutputStream。进程运行正常;但是,每当我尝试将 Process#getInputStream()
和 Process#getErrorStream()
复制到 OutputStream 时,程序就会挂起。
为了调试它,我添加了一个打印语句来在每次迭代时输出缓冲区,如下所示:
public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[4096];
int n = 0;
while ((n = in.read(buffer)) != -1) {
// I have no clue why, but this only works if I print the output to sysdout
System.out.println(new String(buffer));
out.write(buffer, 0, n);
}
}
出于某种奇怪的原因,这样做使一切都按预期进行。尝试刷新 OutputStream,刷新 System.out,或将空字符打印到标准输出,或事件打印普通 byte[] buffer
都不起作用,只有我上面的方法有效。
发生这种情况的代码是怎么回事?
编辑:显示用法
public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {
int status = -1;
Logger logger = Util.getOutputStreamLogger(moduleOut);
logger.info("Starting module {}", getModuleName());
ProcessBuilder exec = new ProcessBuilder();
exec.directory(getWorkingDirectory());
if (configureEnvironment(exec.environment(), moduleOut)) {
List<String> command = getExecutable();
command.addAll(arguments);
exec.command(command);
LOGGER.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
LOGGER.info("In: {}", getWorkingDirectory());
LOGGER.info("Executing: {}", StringUtils.join(command, " "));
Process proc = exec.start();
LOGGER.info("Copying input stream");
copy(proc.getInputStream(), moduleOut);
try {
logger.info("Waiting for process");
status = proc.waitFor();
if (status != 0) {
logger.error("The process failed with the following error: ");
copy(proc.getErrorStream(), moduleOut);
}
logger.info("The process finished with exit code: {}", status);
} catch (InterruptedException e) {
LOGGER.warn("The thread was interrupted", e);
Thread.currentThread().interrupt();
}
} else {
logger.info("Module configuration failed");
}
Util.detachOutputStreamFromLogger(logger);
return status;
}
正如 EJP 所建议的那样,我通过执行程序将流的复制拆分为单独的线程,然后确保在生成的进程完成后关闭它们:
public int runModule(OutputStream moduleOut, int argShowRange, List<String> arguments) throws IOException {
int status = -1;
Logger logger = Util.getOutputStreamLogger(moduleOut);
logger.info("Starting module {}", getModuleName());
ProcessBuilder exec = new ProcessBuilder();
exec.directory(getWorkingDirectory());
if (configureEnvironment(exec.environment(), moduleOut)) {
List<String> command = getExecutable();
command.addAll(arguments);
exec.command(command);
logger.info("With PYTHONPATH: {}", exec.environment().get("PYTHONPATH"));
logger.info("In: {}", getWorkingDirectory());
logger.info("Executing: {}", StringUtils.join(command, " "));
Process proc = exec.start();
try (InputStream procOut = proc.getInputStream(); InputStream procErrOut = proc.getErrorStream()) {
copy(procOut, moduleOut);
copy(procErrOut, moduleOut);
LOGGER.debug("Waiting for process to finish");
status = proc.waitFor();
LOGGER.debug("Closing streams");
procOut.close();
procErrOut.close();
logger.info("The process finished with exit code: {}", status);
} catch (InterruptedException e) {
LOGGER.warn("The thread was interrupted", e);
Thread.currentThread().interrupt();
}
} else {
logger.info("Module configuration failed");
}
Util.detachOutputStreamFromLogger(logger);
return status;
}
public void copy(final InputStream in, final OutputStream out) throws IOException {
executor.execute(() -> {
try {
byte[] buffer = new byte[4096];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
} catch (IOException e) {
LOGGER.error("Ya done goofed", e);
}
});
}