I have a script which executes a program several times, producing about 350 lines of output to both STDERR and STDOUT. Now, I need to execute the script in Java, thereby printing the output streams to their original destinations. So, basically, I execute the script from inside a Java class, maintaining the original behavior for the user.
The way I do this is inspired from suggestions like Reading streams from java Runtime.exec and, functionally, works fine.
Process p = Runtime.getRuntime().exec(cmdarray);
new Thread(new ProcessInputStreamHandler(p.getInputStream(), System.out)).start();
new Thread(new ProcessInputStreamHandler(p.getErrorStream(), System.err)).start();
return p.waitFor();
And the class ProcessInputStreamHandler
:
class ProcessInputStreamHandler implements Runnable {
private BufferedReader in_reader;
private PrintStream out_stream;
public ProcessInputStreamHandler(final InputStream in_stream, final PrintStream out_stream) {
this.in_reader = new BufferedReader(new InputStreamReader(in_stream));
this.out_stream = out_stream;
}
@Override public void run() {
String line;
try {
while ((line = in_reader.readLine()) != null) {
out_stream.println(line);
}
} catch (Exception e) {throw new Error(e);}
out_stream.flush();
}
}
Now regarding my problem statement: While the execution of the script takes about 17 seconds, the "encapsulated" execution takes at least 21 seconds. Where do I lose these 4 or more seconds?
I already tried using a ProcessBuilder
with redirection of STDERR to STDOUT, using POSIX vfork with libraries like https://github.com/axiak/java_posix_spawn, using a byte buffer instead of a BufferedReader
... everything with no positive result at all.
Are there any suggestings? I understand that there will be some performance loss, but 4 seconds seem to be a bit much to me...
Appreciate any suggestions!
Best Regards and Thanks in Advance.
The fastest way for your task is to use Java 7 and
return new ProcessBuilder(cmdarray).inheritIO().start().waitFor();
If that doesn’t help, I think there’s nothing you can do as every other approach would add even more code to your runtime environment that has to be processed.
Don't know if it will improve performance or not, but you can try the NuProcess library which while also providing non-blocking (asynchronous) I/O will also use vfork on Linux, which does decrease process launch times (and memory overhead) quite a bit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With