在 Java 中,使用 Runtime.getRuntime().exec 和 p.waiFor() 会为短任务引入大量开销
In Java does using Runtime.getRuntime().exec and p.waiFor() introduce significant overhead for short tasks
在我的 Java 应用程序中,我有时必须调用非 java 命令行应用程序来处理文件。我经常处理 20 个文件,对于每个文件,我使用 Runtime.getRuntime().exec 到 运行 命令,附加一个进程来监听输出和错误输出并等待任务完成。
在我的 PC 上它工作正常,但在相当慢的 NAS 设备上它似乎更慢 运行通过 Java 执行任务然后如果它们是 运行 直接在命令行中,每个任务持续几秒钟,可能比命令行多一秒钟。随着时间的推移,这种明显的差异是相当大的(注意在 PC 上每个任务只需要大约 200 毫秒)。
从 Java 调用、创建线程来侦听输出并等待完成是否会引入大量开销。我是否应该重写我的代码以创建一个将处理所有文件的脚本,这样我只需要一个 Runtime.getRuntime().exec 和两个 strream gobbler。
困难在于可靠地解析输出,因为我需要考虑任务有时会失败,所以我的问题是是否有任何意义,它会有所作为吗?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class StreamGobbler implements Runnable {
private InputStream inputStream;
private StringBuilder output;
public StreamGobbler(InputStream inputStream, StringBuilder output) {
this.inputStream = inputStream;
this.output = output;
}
@Override
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
try
{
String s = br.readLine();
if (s != null)
{
output.append(s);
}
br.close();
}
catch(IOException ioe)
{
}
}
}
List<String> params = new ArrayList();
params.add(new File(SongKong.exeFolder, "fpcalc").getAbsolutePath());
params.add(file.getPath());
p = Runtime.getRuntime().exec(params.toArray(new String[1]));
StringBuilder output = new StringBuilder();
StringBuilder errorOutput = new StringBuilder();
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), output);
StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), errorOutput);
Executors.newSingleThreadExecutor().execute(outputGobbler);
Executors.newSingleThreadExecutor().execute(errorGobbler);
p.waitFor();
fingerprint = output.toString();
您想知道重写应用程序以执行一个脚本而不是多个 exec 是否会对执行时间产生影响。
应该可以吧。然而,如果不理解为什么执行的命令很慢,我们无法告诉您它会带来多大的不同......以及是否值得付出努力。
我建议你在Java中做一些简单的实验:
比较 运行 一些简单命令(例如 exec("echo hello")
)与执行执行相同操作的脚本相比 20 次:
对存储在 NAS 上的输入文件执行相同操作
对存储在 NAS 上的可执行文件执行相同操作(如果相关)
这些实验应该可以帮助您确定您提出的加速应用程序的方法是否可行。
如果您的外部命令是一个 Java 命令,它在类路径上有很多 JAR,并且这些 JAR 在 NAS 上,那么 可以 显着影响启动时间。
在我的 Java 应用程序中,我有时必须调用非 java 命令行应用程序来处理文件。我经常处理 20 个文件,对于每个文件,我使用 Runtime.getRuntime().exec 到 运行 命令,附加一个进程来监听输出和错误输出并等待任务完成。
在我的 PC 上它工作正常,但在相当慢的 NAS 设备上它似乎更慢 运行通过 Java 执行任务然后如果它们是 运行 直接在命令行中,每个任务持续几秒钟,可能比命令行多一秒钟。随着时间的推移,这种明显的差异是相当大的(注意在 PC 上每个任务只需要大约 200 毫秒)。
从 Java 调用、创建线程来侦听输出并等待完成是否会引入大量开销。我是否应该重写我的代码以创建一个将处理所有文件的脚本,这样我只需要一个 Runtime.getRuntime().exec 和两个 strream gobbler。
困难在于可靠地解析输出,因为我需要考虑任务有时会失败,所以我的问题是是否有任何意义,它会有所作为吗?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class StreamGobbler implements Runnable {
private InputStream inputStream;
private StringBuilder output;
public StreamGobbler(InputStream inputStream, StringBuilder output) {
this.inputStream = inputStream;
this.output = output;
}
@Override
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
try
{
String s = br.readLine();
if (s != null)
{
output.append(s);
}
br.close();
}
catch(IOException ioe)
{
}
}
}
List<String> params = new ArrayList();
params.add(new File(SongKong.exeFolder, "fpcalc").getAbsolutePath());
params.add(file.getPath());
p = Runtime.getRuntime().exec(params.toArray(new String[1]));
StringBuilder output = new StringBuilder();
StringBuilder errorOutput = new StringBuilder();
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), output);
StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), errorOutput);
Executors.newSingleThreadExecutor().execute(outputGobbler);
Executors.newSingleThreadExecutor().execute(errorGobbler);
p.waitFor();
fingerprint = output.toString();
您想知道重写应用程序以执行一个脚本而不是多个 exec 是否会对执行时间产生影响。
应该可以吧。然而,如果不理解为什么执行的命令很慢,我们无法告诉您它会带来多大的不同......以及是否值得付出努力。
我建议你在Java中做一些简单的实验:
比较 运行 一些简单命令(例如
exec("echo hello")
)与执行执行相同操作的脚本相比 20 次:对存储在 NAS 上的输入文件执行相同操作
对存储在 NAS 上的可执行文件执行相同操作(如果相关)
这些实验应该可以帮助您确定您提出的加速应用程序的方法是否可行。
如果您的外部命令是一个 Java 命令,它在类路径上有很多 JAR,并且这些 JAR 在 NAS 上,那么 可以 显着影响启动时间。