2010-11-12 5 views
3

J'ai un programme (en Java) qui a besoin d'utiliser un autre programme plusieurs fois, avec des arguments différents, pendant son exécution. Il est multi-thread, et doit également faire autre chose que d'appeler ce programme pendant son exécution, donc j'ai besoin d'utiliser Java pour le faire.Exécution d'un programme de ligne de commande plusieurs fois en Java - est-ce correct?

Le problème est que tous les appels Runtime.exec() semblent être effectués de manière synchronisée par Java, de sorte que les threads ne sont pas encombrés par les fonctions elles-mêmes, mais par l'appel Java. Ainsi, nous avons un programme d'exécution très lent, mais cela ne gêne pas les ressources système.

Afin de résoudre ce problème, j'ai décidé de ne pas fermer le processus et faire tous les appels à l'aide de ce script:

#!/bin/bash 

read choice 
while [ "$choice" != "end" ] 
do 
    $choice 
    read choice 
done 

Et tous les précédents appels exec sont remplacés par ceci:

private Process ntpProc; 

Initializer(){ 
    try { 
     ntpProc = Runtime.getRuntime().exec("./runscript.sh"); 
    } catch (Exception ex) { 
     //Error Processing 
    } 
} 

public String callFunction(String function) throws Exception e{ 
    OutputStream os = ntpProc.getOutputStream(); 
    String result = ""; 
    os.write((function + "\n").getBytes()); 
    os.flush(); 
    BufferedReader bis = new BufferedReader(new InputStreamReader(ntpProc.getInputStream())); 
    int timeout = 5; 
    while(!bis.ready() && timeout > 0){ 
     try{ 
     sleep(1000); 
     timeout--; 
     } 
     catch (InterruptedException e) {} 
    } 
    if(bis.ready()){ 
     while(bis.ready()) result += bis.readLine() + "\n"; 
     String errorStream = ""; 
     BufferedReader bes = new BufferedReader(new InputStreamReader(ntpProc.getErrorStream())); 
     while(bes.ready()) errorStream += bes.readLine() + "\n"; 
    } 
    return result; 
} 

public void Destroyer() throws exception{ 
    BufferedOutputStream os = (BufferedOutputStream) ntpProc.getOutputStream(); 
    os.write(("end\n").getBytes()); 
    os.close(); 
    ntpProc.destroy(); 
} 

Cela fonctionne très bien, et a réussi à améliorer la performance de mon programme dix fois. Donc, ma question est: est-ce correct? Ou est-ce que je manque quelque chose à propos de faire les choses de cette façon qui fera que tout ira terriblement mal finalement?

+0

utilisez-vous les Java Threads correctement? Je veux dire, appelez-vous start() ou run()? –

Répondre

3

Si vous souhaitez lire les flux d'erreur et d'entrée de processus (alias stderr et stdout), vous devez effectuer ce travail sur des threads dédiés.

Le problème principal est que vous devez vider les tampons au fur et à mesure qu'ils sont remplis, et vous ne pouvez le faire que sur un thread séparé.

Ce que vous avez fait, vous avez réussi à raccourcir la sortie, afin qu'il ne déborde pas ces tampons, mais le problème sous-jacent est toujours là.

De même, l'expérience passée a montré que l'appel de processus externes à partir de Java est extrêmement lent, ce qui fait que votre approche peut être meilleure après tout.

1

Tant que vous n'appelez pas Proccess.waitFor(), l'exécution du processus ne bloque pas. Comme Alex a dit - blocage dans votre cas causé par ces boucles pour lire la sortie.

Vous pouvez utiliser package commons-exec, car il offre un bon moyen de processus en cours d'exécution (synchronisation ou asynchrone), la manipulation sortie, les délais d'attente réglage, etc.

Voici un lien vers un projet: http://commons.apache.org/exec/

le meilleur exemple d'utilisation du api est classe de test, ils ont: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?view=markup

Questions connexes