2011-01-20 31 views
7

VBScriptへの呼び出しをいくつか使用して外部データを取得することはできません。私はクロスプラットフォームの柔軟性を失うので、この実装は本当に嫌いですが、少なくとも問題を緩和するために、同様の* nixスクリプトを開発する可能性があります。誰かが尋ねる前に、はデータを収集するために外部スクリプトを呼び出す必要がありません。私はその原因で生きるだろう。Java - 複数の同時実行時の問題runtime.exec()InputStreams

exec()のプロセスは、Runnableに拡張されたカスタムクラスで実行されます。これはBufferedReaderを使用してgetInputStream()のデータを読み込みます。

編集:要求としてより多くのコードを追加しましたが、私は余分なコードが関連している方法を見ていない:)それはフォーマットするしばらく時間がかかったので、私は、それが役に立てば幸い!それは醜いだが、建設的な批判が奨励されている場合、私は、個々のコマンドを実行するとああ、と私は期待して私がデータを収集し、...私のコードのスタイルに

public class X extends JFrame implements Runnable { 

    ... 
    static final int THREADS_MAX = 4; 
    ExecutorService exec; 
    ... 
    public static void main(String[] args) { 
     ... 
     SwingUtilities.invokeLater(new X("X")); 
    } // End main(String[]) 

    public X (String title) { 
     ... 
     exec = Executors.newFixedThreadPool(THREADS_MAX); 
     ... 

     // Create all needed instances of Y 
     for (int i = 0; i < objects.length; i++) { 
     Y[i] = new Y(i); 
     } // End for(i) 

     // Initialization moved here for easy single-thread testing 
     // Undesired, of course 
     for (int i = 0; i < objects.length; i++) { 
     Y[i].initialize(parent); 
     } // End for(i) 

    } // End X 

    class Y implements Runnable { 
     // Define variables/arrays used to capture data here 
     String computerName = ""; 
     ... 

     public Y(int rowIndex) { 
     row   = rowIndex; 
     ... 
     computerName = (String)JTable.getValueAt(row, 0); 
     ... 
     exec.execute(this); 
     } // End Y(int) 

     public void run() { 
     // Initialize variables/arrays used to capture data here 
     ... 

     // Initialization should be done here for proper threading 
     //initialize(parent); 
     } // End run() 

     public void initialize(Z obj) { 
     runTime = Runtime.getRuntime(); 
     ... 

     try { 
      process = runTime.exec("cscript.exe query.vbs " + computerName); 
      stdErr = process.getErrorStream(); 
      stdIn = process.getInputStream(); 
      isrErr = new InputStreamReader(stdErr); 
      isrIn = new InputStreamReader(stdIn); 
      brErr = new BufferedReader(isrErr); 
      brIn = new BufferedReader(isrIn); 

      while ((line = brIn.readLine()) != null) { 
       // Capture, parse, and store data here 
       ... 
      } // End while 

     } catch (IOException e) { 
      System.out.println("Unable to run script"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       stdErr.close(); 
       stdIn. close(); 
       isrErr.close(); 
       isrIn. close(); 
       brErr. close(); 
       brIn. close(); 
      } catch (IOException e) { 
       System.out.println("Unable to close streams."); 
      } // End try 
     } // End try 
     } // End initialize(Z) 
     ... 
    } // End class Y 
} // End class X 

を簡単に行きます。しかし、クラスのrun()ブロック内のコマンドを実行すると(呼び出しが並行していることを意味します)、入力ストリームが1つだけ生成されたように見えますが、すべてBufferedReadersが同時に消費されます。

問題をデバッグするために、私は、入力ストリームを読み込んでいたクラスのインスタンスが前に付いたコンソールで、各消費された行を出力します。私は、彼らがからインスタンスとインスタンスのための外にあってもよいことを理解、以下のようなものを期待していますが、単一インスタンスの行の順序はそのまま次のようになります。

exec 0: Line1 
exec 1: Line1 
exec 2: Line1 
exec 0: Line2 
exec 1: Line2 
exec 2: Line2 
exec 0: Line3 
exec 1: Line3 
exec 2: Line3 
... 

奇妙だ私は何の期待数を取得されます出力の最初の行(Microsoft (R) Windows Script Host Version 5.7)のインスタンスですが、この行の後に入力ストリームにデータを生成するプロセスは1つだけで、次の例のようにすべてのリーダーがこの1つのストリームを無作為に消費します。

exec 2: Microsoft (R) Windows Script Host Version 5.7 
exec 0: Microsoft (R) Windows Script Host Version 5.7 
exec 1: Microsoft (R) Windows Script Host Version 5.7 
exec 0: line2 
exec 1: line3 
exec 2: line4 
... 

さらに悪いことに、読者のストールとreadLine()は決してnullを返しません。私は、このタイプの振る舞いはバッファサイズと関係があるかもしれないと読んでいますが、短い出力でも2つの並行スレッドしか実行しない場合でも、同じ動作を示します。 stdErrには何も記録されておらず、問題があることを示しています。

これがスクリプトホストの制限事項であるかどうかを確認するために、START複数のスクリプトインスタンスを同時に実行するバッチファイルを作成しました。 これは、cmdシェルでがJavaの以外で実行されたことを示す必要があり、いくつかの独自のシェルを起動します。しかし、各同時実行インスタンスは、期待される結果を完全に返し、うまく動作しました。

編集:別のトラブルシューティングのアイデアとして、私は再度有効に同時実行することにしましたが、私のY.run()ブロックに次のように挿入して、私の初期化メソッドをずらす:私のコードに

try { 
    Thread.sleep((int)(Math.random() * 1200)); 
} catch (InterruptedException e) { 
    System.out.println("Can't sleep!"); 
} // End try 
initialize(monitor); 

。最初の数行は複数の出力を見始めるが、同じプロデューサを消費する複数の消費者にすばやく戻って、最初の完了したストリームが閉じられるとすぐに残りのコンシューマが例外を発生させる。次の消費者はIOException: Read errorを発射し、残りはIOException: Stream closedを発射する!

はmaaartinusによると、今の質問は望ましくない動作の原因になっているものになり、複数の実行に並行InputStreamsことは可能ですか?どのようにして独立して入力ストリームを取得できますか?私はそれを避けることができれば、データを処理するために一時ファイルに書き込む必要はありません。

+1

'だから私は混乱している - ?複数の入力を処理することが可能なJavaは、同時にか流れている'確かに、それはあります。 Windows Script Hostに何か問題がある可能性があります。私は簡単なスクリプト(または別のプログラム)を試して、簡単な出力を得ようとしています。 – maaartinus

+1

いくつかのフィールドが静的であるように聞こえるのは間違いです。もっとクラスを投稿できますか? –

+1

'さらに悪いことに、読者が失速とのreadLine()プロセス当たり、すなわち、二つのスレッド、各ストリームに自身のスレッドを使用してみてくださいnull.'返すことはありません。各ストリームに小さなバッファがあり、プロセスがいっぱいになるとブロックされます(もう一方のストリームから何も得られません)。 – maaartinus

答えて

5

私はあなたがIO変数のスコープについて注意する必要があると思います。 (; javaのMultiExec%のjavacのMultiExec.java)

ここ4子プロセスからの同時入力ストリームで、完璧にうまく機能迅速なコード...上記のコードから

import java.io.*; 

public class MultiExec { 

     private final static String[] comLines = { 
         "date", 
         "ls /var/spool/postfix", 
         "ls -F /usr/local/bin", 
         "wc -l /etc/apache2/apache2.conf"}; 

     public void execute() { 
       for (int i = 0 ; i < comLines.length ; i++) { 
         ExecutableChild ec = new ExecutableChild (i, comLines[i]); 
         new Thread (ec).start(); 
     }} 

     public class ExecutableChild implements Runnable { 

       private int prIndex; 
       private String executable; 

       public ExecutableChild (int k, String cmd) { 
         prIndex = k; 
         executable = cmd; 
       } 

       public void run() { 
         try { 
           Process child = Runtime.getRuntime().exec(executable); 
           BufferedReader br = new BufferedReader (new InputStreamReader (
                   child.getInputStream())); 
           for (String s = br.readLine() ; s != null ; s = br.readLine()) 
             System.out.println ("[" + prIndex + "] " + s); 
           br.close(); 
         } catch (IOException ioex) { 
           System.err.println ("IOException for process #"+ 
               prIndex+ ": " + ioex.getMessage()); 
     }}} 

     public static void main (String[] args) { 
       new MultiExec().execute(); 
     } 
} 

出力がありますあなたの試みのためのソースコードを入手したら、それについて議論することができます。良い願い、 - M.

============================================== ===============

編集: DN:私は1行出力に関する懸念を理解しています。 ...

#!/usr/bin/perl -w 
foreach (1..50) { 
     print "$_\n"; 
} 

とJavaコード上での編集されたバージョンを小さなスクリプトを持っています...( comLinesは変更されている、とのThread.sleepは、すべてのprintlnの後に追加)

パブリッククラスMultiExec {ここで

 private final static String[] comLines = { 
         "ls /var/spool/postfix", 
         "perl count50.pl", 
         "cat MultiExec.java", 
         "head -40 /etc/apache2/apache2.conf"}; 

     public void execute() { 
       for (int i = 0 ; i < comLines.length ; i++) { 
         ExecutableChild ec = new ExecutableChild (i, comLines[i]); 
         new Thread (ec).start(); 
     }} 

     public class ExecutableChild implements Runnable { 

       private int prIndex; 
       private String executable; 

       public ExecutableChild (int k, String cmd) { 
         prIndex = k; 
         executable = cmd; 
       } 

       public void run() { 
         try { 
           Process child = Runtime.getRuntime().exec(executable); 
           BufferedReader br = new BufferedReader (new InputStreamReader (
                   child.getInputStream())); 
           for (String s = br.readLine() ; s != null ; s = br.readLine()) { 
             System.out.println ("[" + prIndex + "] " + s); 
             try { 
               Thread.sleep (20); 
             } catch (InterruptedException intex) { 
           }} 
           br.close(); 
         } catch (IOException ioex) { 
           System.err.println ("IOException for process #"+ 
                   prIndex+ ": " + ioex.getMessage()); 
     }}} 

     public static void main (String[] args) { 
       new MultiExec().execute(); 
}} 

は今(コンパイル/実行後に)出力されます...

[0] active 
[1] 1 
[2] import java.io.*; 
[3] # 
[2] 
[0] bounce 
[1] 2 
[3] # Based upon the NCSA server configuration files originally by Rob McCool. 
[2] public class MultiExec { 
[1] 3 
[0] corrupt 
[3] # 
[1] 4 
[2] 
[0] defer 
[3] # This is the main Apache server configuration file. It contains the 
[2]  private final static String[] comLines = { 
[0] deferred 
[1] 5 
[3] # configuration directives that give the server its instructions. 
[2]      "ls /var/spool/postfix", 
[0] etc 
[1] 6 
[3] # See http://httpd.apache.org/docs/2.2/ for detailed information about 
[2]      "perl count50.pl", 
[0] flush 
[1] 7 
[3] # the directives. 
[2]      "cat MultiExec.java", 
[1] 8 
[0] hold 
[3] # 
[1] 9 
[2]      "head -40 /etc/apache2/apache2.conf"}; 
[0] incoming 
[3] # Do NOT simply read the instructions in here without understanding 
[2] 
[0] lib 
[1] 10 
[3] # what they do. They're here only as hints or reminders. If you are unsure 
[1] 11 
[2]  public void execute() { 
[0] maildrop 
[3] # consult the online docs. You have been warned. 
[2]    for (int i = 0 ; i < comLines.length ; i++) { 
[0] pid 
[1] 12 
[3] # 
[1] 13 
[2]      ExecutableChild ec = new ExecutableChild (i, comLines[i]); 
[0] private 
[3] # The configuration directives are grouped into three basic sections: 
[1] 14 
[2]      new Thread (ec).start(); 
[0] public 
[3] # 1. Directives that control the operation of the Apache server process as a 
[2]  }} 
[1] 15 
[0] saved 
[3] #  whole (the 'global environment'). 
[1] 16 
[0] trace 
[2] 
[3] # 2. Directives that define the parameters of the 'main' or 'default' server, 
[0] usr 
[2]  public class ExecutableChild implements Runnable { 
[1] 17 
[3] #  which responds to requests that aren't handled by a virtual host. 
[0] var 
[2] 
[1] 18 
[3] #  These directives also provide default values for the settings 
[1] 19 
[2]    private int prIndex; 
[3] #  of all virtual hosts. 
[1] 20 
[2]    private String executable; 
[3] # 3. Settings for virtual hosts, which allow Web requests to be sent to 
[2] 
[1] 21 
[3] #  different IP addresses or hostnames and have them handled by the 
[1] 22 
[2]    public ExecutableChild (int k, String cmd) { 
[3] #  same Apache server process. 
[1] 23 
[2]      prIndex = k; 
[3] # 
[1] 24 
[2]      executable = cmd; 
[3] # Configuration and logfile names: If the filenames you specify for many 
[2]    } 
[1] 25 
[3] # of the server's control files begin with "/" (or "drive:/" for Win32), the 
[2] 
[1] 26 
[3] # server will use that explicit path. If the filenames do *not* begin 
[1] 27 
[2]    public void run() { 
[3] # with "/", the value of ServerRoot is prepended -- so "/var/log/apache2/foo.log" 
[1] 28 
[2]      try { 
[3] # with ServerRoot set to "" will be interpreted by the 
[1] 29 
[2]        Process child = Runtime.getRuntime().exec(executable); 
[3] # server as "//var/log/apache2/foo.log". 
[1] 30 
[2]        BufferedReader br = new BufferedReader (new InputStreamReader (
[3] # 
[1] 31 
[2]                child.getInputStream())); 
[3] 
[1] 32 
[2]        for (String s = br.readLine() ; s != null ; s = br.readLine()) { 
[3] ### Section 1: Global Environment 
[1] 33 
[2]          System.out.println ("[" + prIndex + "] " + s); 
[3] # 
[1] 34 
[2]          try { 
[3] # The directives in this section affect the overall operation of Apache, 
[1] 35 
[2]            Thread.sleep (20); 
[3] # such as the number of concurrent requests it can handle or where it 

...... 

入力ストリームはうまく動作していますが、ここで問題がないとは思われません。返事がとても長くなるのは残念です。最善を尽くし、あなたのコードを見るのを待っています - M.S.

+0

私は、あなたが使った例がa)cscriptコマンドほど複雑ではなく、b)1つの例を除いてすべて1行を返すことに気付くことはできません。すべての目的と目的のために、技術的には同様の問題を抱えている可能性があります:)とにかく、ほとんどすべてのコードです。残りのクラス変数は、抽出されたデータを格納するためのものであり、すべてのコンストラクタまたはメソッドの外部で定義されています(静的ではありません)。私は、会話を動かすのに役立つもう少し多くの構造(多くのものは無関係です)を掲示します。これまでのあなたの努力は非常に高く評価されています! –

+0

こんにちは再びDN、改訂された返信がそこに掲載されます。助けになるのはうれしい –

+0

それは明らかに残りの部分を書くために半時間(私はその部分のために忙しかった)以上の時間をかかりました。時間をかけて、私は今夜もっと見ることができません。 :P –

3

は、あなたが正しい範囲にstdErrstdInを宣言していることを確認します。この場合は、Yで宣言する必要があります。

あなたがXでそれらを宣言している場合は、次のコードを実行するたび:

stdErr = process.getErrorStream(); 
stdIn = process.getInputStream(); 

は、変数が再割り当てされます、そしてYのすべてのインスタンスが同じストリームを参照します。

+1

これは、私が職業によってプログラマーではない理由を説明するこのような単純なエラーです。しかし、私が上で述べたように、彼はこれに最初に答えました。私はそれを認識しませんでした。ありがとうございました! –

関連する問題