multiple processbuilder in a programme - java

i want to use two process builder in same program how can i do this both processbuilder are performing different task on same file how can i execute both together.
ProcessBuilder pb = new ProcessBuilder( "nusmv ", "inputfile.smv");
Process p = pb.start();
ProcessBuilder pb123 = new ProcessBuilder("nusmv","-int","inputfile.smv");
Process process123 = pb123.start();
it is just executing first processbuilder second one has been ignored.

There are two issues which I can think of:
1. call process.waitFor() for the process so that each one gets completed before starting other.
2. Flush the output and error streams of one process before proceeding to the other.Many operating systems provide limited memory buffer for standard input and output streams. So if you do not flush or process the streams immediately they might cause the process to block or even deadlock.
For more info u can refer this link.
http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html

Related

How to improve performance of Java Process?

Hello stackoverflow community,
I try to run a command on the console and read the input stream of this process:
String command[] = {"ffmpeg"}; //minimal command example
Process proc = processBuilder.command(command).start();
byte[] bytes = IOUtils.toByteArray(proc.getInputStream());
proc.waitFor();
The command is a very long ffmpeg command, which prints bytes to the output. Everything works just fine, but it is very slow using java. When I run this command on my regular command line tool, it takes round about 20ms, everything is printed and done.
For the Java process is takes more than 2s. I also tried to redirect all I/O streams to the std, but the performance is the same, since I thought my reading is too slow. Also, reading the stream in additional threads or using other stream readers etc. did not change anything. The only thing which has an effect is adding cmd (currently working with Windows 10) to the command:
String command[] = {"cmd","/C","ffmpeg"};
resulting in a execution time of round about 400ms. I did not know before that this makes a difference, but it really does.
Since this is a Spring Boot web application and the command is used to output images from a video, 400ms is still a lot. The issue here is, that the frontend/browser requests a bunch of images (lets say 36). Apparently the simultaneous requests of a browser to one host is limited (chrome 6 requests), see here. Therefore it takes at best 6 x 400ms to deliver the content.
So is there a way to improve the performance to the java process or maybe keep it open and fire commands to avoid overhead?
Here is the pseudo code to your question in the comments above:
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProcessBuilder pb = new ProcessBuilder(command);
// Consuming STDOUT and STDERR in same thread can lead to the process freezing if it writes large amounts.
pb.redirectErrorStream(true);
Process process = pb.start();
try (var infoStream = process.getInputStream()) {
infoStream.transferTo(out);
}
status = process.waitFor();
if (status > 0)
// errorhandling
#transferTo(out) Consumes the output stream inside the processbuilder thread. That's it! It runs inside the thread of process.

How to wait for a process in Java [duplicate]

This question already has answers here:
Wait for process to finish before proceeding in Java
(4 answers)
Closed 3 years ago.
In the following code, I tried to execute a script, which takes quite a while to finish.So, I already tried to use process.waitfor() but it didn't let the script finish. Are there any ideas how to make it work?
ProcessBuilder pb = new ProcessBuilder(osShell);
Process process = pb.start();
PrintWriter pyCon = new PrintWriter(process.getOutputStream());
pyCon.println("cd " + videoDir);
System.out.println("Executing python file: "+ command);
pyCon.println(command);
//Here, I need a piece of code which let's my command run in peace
pyCon.close();
System.out.println(convertStreamToString(process.getInputStream()));
process.waitFor();
By closing the stdin of the shell process, you pretty much told it it's over. Chances are the shell ended killing the child python cmd, or at least not draining nor forwarding the python stdout/stderr to its own shell stdout/stderr.
Try waiting for some expected end marker from your python cmd. Then only close stdin. Drain all the stdout/stderr from the process of course.
It common to see 2 more threads just to pump out the bytes from stdout/stderr while the main thread is controlling/waiting for the process. Keep in mind that if you don't pump the bytes out, the pipes may fill up and block on the child side, preventing it from terminating. These pipes are often pretty small (512 to 2k bytes for instance - that is obviously testable).
Sending commands to a shell’s standard input is unlikely to work, especially in Windows.
The correct way to execute something in a particular directory is not by trying to send a cd command, but by specifying the directory in the ProcessBuilder itself:
ProcessBuilder pb = new ProcessBuilder("python", pythonFileName);
pb.directory(new File(videoDir));
Process process = pb.start();

How to stop an input-waiting Windows batch process in Java?

I have a Windows batch file simple.bat which produces some output in stdin, and ends with a pause. I want to run this batch file and then process the output in my Java code.
// create a Java process with simple.bat
Process p = Runtime.getRuntime().exec("cmd /c simple.bat");
// get the output from the process p
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
The problem with the above code is that simple.bat ends with a pause and that makes p still hanging in there waiting for the key to be pressed. As a result, eventually reader.readLine() will be blocked and never returns.
Unfortunately, simple.bat is passed on to me as-is. I cannot remove the pause line.
I can add
Thread.sleep(1000);
p.destroy();
after the exec("cmd /c start simple.bat") line to terminate the process p before processing its output. What if the batch file is run on slow machine? I am seeking advice is there a better way then asynchronously stopping the process. Thank you very much!!
If your script doesn't require any input sent to it, and you are running it as cmd /c simple.bat, then the simplest thing to do is to close the process's standard input:
p.getOutputStream().close();
I ran a quick test myself, and this dismissed the pause and let the script terminate. You will of course have the extra line Press any key to continue . . . in your output, but I imagine you can deal with that.
Destroying the process can be correct as a fallback. You will have to think about how you would prefer your application to fail: is aborting to soon worse than a hanging process? Which of the failures will the user actually notice?
In most cases both of the above are undesirable.
If you know you have reached the pause (based on the last readline()), you can actually write to the process. This can be done by getting an output stream Process.getOutputStream(). I haven't been able to test this, but normally pause should also react to characters written this stream.

How to inherit the standard output to a child process efficiently in java?

In Java, I want to invoke the grep command and send its output to the stdout. I can do this:
ProcessBuilder pb = new ProcessBuilder("grep", "regexp", "foo.txt");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.start().waitFor();
However, the stdout of the grep process is actually piped to the java process and then printed. This can be inefficient when the data is huge.
A dirty way is to find the stdout of the java process (e.g. by readlink(/proc/self/fd/1)) and then call pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(MYSTDOUTFILE)));, but is there a better way?

How to wait for a batch file processing to end which is executed using Runtime.exec or ProcessBuilder.start, before moving to the next statement?

I have written a small application for a project..that will do following tasks:
Writes a commands.bat file. This bat file has some source-code-server commands that will take sometime to get process.
Executes the commands.bat using ProcessBuilder and get outputfile.txt using redirectOutput(File file) method.
Reads the outputfile.txt and get the desired output.
When I run this application, the program control starts with step-1 and executes it completely. In step-2 the control starts a process that drives the batch file. Now commands.bat file takes some time to finish (depends on the response from source code server). Sometimes this batch takes a little more than the reasonable time, for which the control is not waiting and starts executing step-3, and this way I am not getting the complete stream in the outfile.txt.
I also used things like:
waitfor(): Even with this control is not waiting for process to end(technically I may be wrong)
Thread.sleep(). This is not working as time taken in batch file processing is not certain.
Please help.
This is how I am waiting for a batch file to execute. Hopefully you have solved the problem by now. But, it might help someone else who looks at this question
// Any command you want to run in my case im executing a batch file
String cmd = "load_execute.bat";
//FILE_PATH is the directory where to starting from
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", cmd).redirectErrorStream(true);
builder.directory(new File(FILE_PATH));
Process process = builder.start();
//Redirect stream from cmd stream to local print stream
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
res = process.waitFor();`

Categories