- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我别无选择,只能通过对 VBScript 的多次 Runtime.exec()
调用来检索一些外部数据。我真的很讨厌这个实现,因为我失去了跨平台的灵 active ,但我最终可能会开发类似的 *nix 脚本来至少缓解这个问题。在任何人询问之前,我无法解决调用外部脚本来收集数据的需要。我会忍受由此产生的问题。
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()
block 中执行命令(这意味着调用是并发的,正如我所希望的那样),看起来好像只生成了一个输入流,所有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
),但在这一行之后,只有一个进程继续在输入流中产生数据,所有读者随机消费这个流,例如这个例子:
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。我读到这种行为可能与缓冲区大小有关,但是当我只运行两个并发线程时,即使输出很短,它仍然表现出相同的行为。 stdErr
中没有捕获任何内容来指示存在问题。
为了查看这是否是脚本宿主的限制,我创建了一个批处理文件,该批处理文件同时START
s 多个脚本实例。 我应该声明这是在 Java 的之外运行的,在一个 cmd shell 中,并启动了它自己的几个 shell。但是,每个并发实例都完全返回了预期的结果并且表现良好.
编辑:作为另一个故障排除想法,我决定重新启用并发,但通过将以下内容插入我的 Y.run()
block 来错开我的初始化方法:
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
是可能的,所以现在的问题是什么导致了不希望的行为?我怎样才能独立地抓取他们的输入流?如果可以避免的话,我不想为了处理返回的数据而写入临时文件。
最佳答案
我认为您需要注意 IO 变量的范围。这是一个运行良好的快速代码,具有来自 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();
}
}
以上代码的输出(% javac MultiExec.java; java MultiExec)
[2] tomcat*
[0] Thu Jan 20 18:38:31 CST 2011
[3] 368 /etc/apache2/apache2.conf
[1] active
[1] bounce
[1] corrupt
[1] defer
[1] deferred
[1] etc
[1] flush
[1] hold
[1] incoming
[1] lib
[1] maildrop
[1] pid
[1] private
[1] public
[1] saved
[1] trace
[1] usr
[1] var
如果您为我们提供了您尝试的源代码,我们可以讨论它。祝你好运,- M.S.
============================================= ==============================
编辑:DN:我理解您对 1 线输出的担忧。让我们有一个小脚本...
#!/usr/bin/perl -w
foreach (1..50) {
print "$_\n";
}
以及上述 Java 代码的编辑版本...comLines 已经改变,并且在每个 println() 之后添加了一个 Thread.sleep
公共(public)类 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.
关于Java - 多个并发 runtime.exec() InputStreams 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4753901/
我在内存中有一个 Map 来存储我的对象。我想在内存不足时刷新内存。我现在正在这样做: void add(K key, V value) { if (underPressure()) {
我是 JBPM 的新手。我下载并开始使用 eclipse。然后我安装了 JBPM 插件和 Modeler 2.0 插件。当我创建一个新的 JBPM 项目时,它要求 JBPM 运行时。我在互联网上搜索了
我是 JBPM 的新手。我下载并开始使用 eclipse。然后我安装了 JBPM 插件和 Modeler 2.0 插件。当我创建一个新的 JBPM 项目时,它要求 JBPM 运行时。我在互联网上搜索了
我目前正在将Windows 8.1应用程序移植到Windows 10 UAP应用程序,该应用程序使用互操作在C++和C#之间进行通信,并且 pop 以下错误: $(ProjectName).Inter
我正在使用 Parcel 来捆绑我的项目并 Jest 运行我的测试。 一切正常,但在测试中我有 async/await关键字,我必须导入 regenerator-runtime/runtime像这样:
一旦我尝试使用 Promises,Browserify 就会抛出此错误。 在 中找不到模块“regenerator-runtime/runtime” 我尝试过 Node 版本 10.15.3 和 12
我目前正在试验 quarkus,找不到在运行时更改一些 openapi 信息的方法(这里,我希望授权 url 根据环境而改变)。 应该可以通过使用 OASFilter 并从环境变量中提供信息来实现,但
我正在使用 rust_bert 汇总文本。我需要使用rust_bert::pipelines::summarization::SummarizationModel::new设置模型,该模型可以从互联网
我正在 Visual Studio 中处理其中一个新的“类库(NuGet 包)”项目。一切都很顺利,直到前几天它开始引发有关 System.Runtime.Extensions 程序集的错误: Ass
我正在使用 tokio::runtime::current_thread::Runtime我希望能够在同一个线程中运行 future 并停止 react 堆。页面上的示例未显示如何停止运行时。有什么办
我找不到如何声明 runtime.LockOSThread()和 runtime.UnlockOSThread() .我将其定义为 [runtime.LockOSThread()] 一些代码 [run
我有这样的代码, Routine 1 { runtime.LockOSThread() print something send int to routine 2 runtime.UnlockOSTh
我正在尝试执行此操作:当我单击“搜索”按钮时,命令提示符窗口打开。 我尝试使用ProcessBuilder,没有出现错误,但是不起作用。你能帮我一下吗? package sys.tool; impor
我的应用程序运行大约 4 小时后出现此错误。我不知道为什么会这样。该错误发生在 windows 7 和 windows XP 系统上。抱歉,我没有更多信息。我的应用程序运行大约 4 次后才收到此错误消
我收到错误:“此程序集是由比当前加载的运行时更新的运行时构建的,无法加载。” 我有一个 .NET 2.0 项目调用的 .NET 4.0 dll 项目。有没有办法调和框架的差异? 最佳答案 I have
我有一个 WIX 安装程序,它在安装过程中执行自定义操作。当我运行 WIX 安装程序并遇到它的第一个自定义操作时,安装程序失败,我在 MSI 日志中收到如下错误: Action start 12:
我正在尝试提交 spark 作业 它是这样开始的: import javax.xml.parsers.{SAXParser, SAXParserFactory} import org.apache.s
我正在做一些 WCF 工作,但我不明白为什么会遇到这个错误。 System.Runtime.Serialization.DataContractAttribute命名空间中不存在 System.Run
我尝试按照 this 在 React 应用程序中使用 async/await : 目前,我正在运行webpack --config webpack.dev.config.js --watch --pr
我已经从托管的 Window Server 2008 下载了已发布的(代码隐藏文件不存在,与 bin 文件夹中的 dll 结合)Web 应用程序,并在调试该应用程序时使用 Visual Studio
我是一名优秀的程序员,十分优秀!