Efficient execution and output stream redirection

2019-01-18 07:40发布

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.

2条回答
The star\"
2楼-- · 2019-01-18 08:35

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.

查看更多
等我变得足够好
3楼-- · 2019-01-18 08:41

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.

查看更多
登录 后发表回答