tags:

views:

82

answers:

6

Hello,

In my program, I need to run a external command in a Ubuntu environment (ntpdate) using java. Currently my code looks like this:

    Runtime rt = Runtime.getRuntime();

    byte[] readBuffer = new byte[131072];
    // Exec a process to do the query
    Process p = null;
    try {
        p = rt.exec("ntpdate -q " + ip);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    if(p!= null){
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }

        // Read the input stream, copy it to the file
        InputStream in = p.getInputStream();


        try {
            int count = 0, rc;
            while ((rc = in.read(readBuffer, count, readBuffer.length - count)) != -1) {
                count += rc;
                if (count >= readBuffer.length) {
                    p.destroy();
                    break;
                }
            }
            p.destroy();
            result = processOutput(readBuffer, count);

        } catch (IOException ex) {
            ex.printStackTrace();
        }
        p.destroy();

This code need to be ran simultaneously on multiple threads in order to maximize performance (I need to test a list of 1.000.000 addresses using ntpdate). However, it runs very slowly, barely consuming machine processing. What am I doing wrong? How could I make this more efficient?

The same problem arises when trying to execute "dig" using .exec(), so I doubt it is because of the specific program being called. Is there some restriction in using Runtime.exec() in a multi Threaded environment?

+2  A: 

Is Java the most appropriate approach here? Perhaps this would be better in a shell script, which calls ntpdate in the background multiple times? I'm not sure what benefit you're getting from this code snippet by doing this in Java.

What are you doing with the InputStream from the process?


A bash script could do this like:

for ip in #...IP list
do
  ntpdate -q $ip > $ip.txt &
done
Noel M
I need to parse the output data and insert it into a database. Also, the data comes from a database. I am using Java since I had a already built framework to do similar tests, but without using external calls. It could be made on shell script, but I hoped to find a solution for Java, since he same problem happens on another case, in which I can't use shell script.
Phadek
Perhaps the best approach then is to use an java ntp library and forgo using the shell command at all. For ntp http://commons.apache.org/net/ seems like a reasonable approach. It's more portable to not rely on the OS shell commands anyway.
Bill
+1  A: 

Why are you waiting for 1 second at each time ?

try {
    Thread.sleep(1000);
} catch (Exception e) {
}

This will do nothing but slowing the execution of your application.

Colin Hebert
As well as "barely consume machine processing"
Mark Peters
I am trying to fix someone else code. Can't remember why that is there, but removing it does nothing to fix the problem.
Phadek
Are your threads started properly ?
Colin Hebert
I am using a generic thread initialization class, that works on other cases. I seems that the threads, which should be independent of one other, are locking each other when I try to call Runtime.exec()
Phadek
+1  A: 

Not sure why it's slow but you need to do a lot more to close your resources. Runtime.exec() needs quite a bit of care and attention to avoid hang-ups and leaking of file descriptors.

http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html

Matthew Wilson
Gonna try consuming the stderr in another thread.
Phadek
+1  A: 

Are you sure the issue isn't ntpdate? If ntpdate is just sitting there waiting for a server response and has a large timeout value, then your application is going to sit there too.

Try calling ntpdate with a timeout of 0.2 and see if it makes a difference.

Also, as you're opening streams in your code, you definitely want to explicitly .close() them when you're done. Otherwise it might not happen until a GC which could be a very long time away.

locka
I am calling it in multiple threads because of the timeout. However, I am not even able to start all the threads I had setup, as if something was blocking the other threads.But thanks for remembering me about closing the streams.
Phadek
How many threads are you talking about. Perhaps it should be a tweakable value. If you have 1 million you might need to be spawning 500 threads in parallel to get through the list in a day. It might a good idea to consider using a thread pool style architecture to control it. With Java 5 concurrency, you might use a blocking queue and an executor service to spawn a tunable number of workers. Every time one task finishes you can queue up a new address for the next thread which is free.
locka
Yeah, that is what I'm using. However, the threads don't even finish launching before about halfway the list has been processed. I get about the same result (timewise) with anywhere from 100 to 2000 threads.
Phadek
A: 

I notice that both of the commands you tried involve network round-trips. How is the speed if you call something like echo or cat instead?

TMN
Just tested that. If I launch lots of echos in multithread the overall time to complete them all rises the more parallel they are. An Interesting experiment: wait 1 second before trying to do the echo in each thread. the time it took was 6x what it would take for them to execute sequentially.The same holds for every other thing I tried to run with exec, far more than I can explain. I seems to be some problem with java exec implementation. Are there any alternatives?
Phadek
A: 

I think I found the solution, and that is that there is no solution using java's Runtime.exec(). The problem seems to be that all calls to start a process are synchronized. Indeed, if you start each process alone (via synchronization) you get the exact same result of starting all processes together.

Are there any alternatives to exec? Otherwise, I will need to get some solution without linux's ntpdate...

Phadek