为啥 InputStreamReader 不实时读取进程的输出?
Posted
技术标签:
【中文标题】为啥 InputStreamReader 不实时读取进程的输出?【英文标题】:Why InputStreamReader doesn't read process' output in real time?为什么 InputStreamReader 不实时读取进程的输出? 【发布时间】:2013-01-05 13:38:13 【问题描述】:我正在尝试使用 ProcessBuilder
运行一些外部命令,例如 Linux 中的 ifstat
或 vmstat
。
此类命令支持自定义采样间隔。如果我在外部命令中添加一个采样间隔,例如ifstat 20
,那么命令将输出如下:
coolcfan@coolcfan-PC:~$ ifstat 20
eth0 wlan0 vmnet1 vmnet8
KB/s in KB/s out KB/s in KB/s out KB/s in KB/s out KB/s in KB/s out
20 秒后
41.29 1.06 0.36 0.00 0.00 0.00 0.00 0.00
再过 20 秒
16.67 0.58 0.38 0.00 0.00 0.00 0.00 0.00
然而,当我使用我的 Java 代码运行命令时,将在 20 秒后读取输出的第一部分,如下所示:
Start running "ifstat 20"
20 秒后
eth0 wlan0 vmnet1 vmnet8
KB/s in KB/s out KB/s in KB/s out KB/s in KB/s out KB/s in KB/s out
66.61 1.73 1.29 0.01 0.00 0.00 0.00 0.00
当我使用 NIO 服务器运行命令并使用 SocketChannel 将输出发送到客户端时,问题更加严重...(我的客户端需要再等待 20 秒才能从服务器获取输出显示进程开始后 20 秒的第一个输出)
而且我注意到输出延迟的长度与我为命令设置的时间间隔有关。
那么为什么 ISR 不实时读取输出呢?
一个简单的测试代码sn-p来演示我的问题:
public static void main(String[] args)
ProcessBuilder pb = new ProcessBuilder();
pb.command("ifstat 20".trim().split(" "));
Process p = null;
System.out.println("Start running \"ifstat 20\"");
try
p = pb.start();
char[] buf = new char[512];
InputStreamReader isr = new InputStreamReader(p.getInputStream());
int count = -1;
while ((count = isr.read(buf, 0, buf.length)) != -1)
System.out.print(new String(buf, 0, count));
catch (IOException ioe)
更新:
正如彼得所说,这不是与 Java 相关的问题。这是一个管道延迟。
但我还是不明白,为什么vmstat 20 | cat
没有这个延迟,而ifstat 20 | cat
会延迟显示头像?
【问题讨论】:
ISR 读取你得到的任何东西。为了比较,运行ifstat 20 | cat
以便它写入管道而不是控制台。
@PeterLawrey 所以这是管道问题?其实我需要在现实环境中运行ifstat 120
...
数据似乎没有延迟,只有标题。
@PeterLawrey 好的,好吧,是的.. 但是为什么头部延迟显示?
我怀疑它没有明确刷新。写入控制台时会自动刷新,但写入管道时需要显式刷新,直到出现第一行数据。
【参考方案1】:
确实如此。
延迟的是进程的输出。 STDIO 进行缓冲,根据 stout 是否为终端而有所不同。
【讨论】:
@coolcfan fflush() 在 C 程序中。你在外面无能为力。 您唯一能做的就是下载 ifstat 的源代码,在写入标头后添加一个 fflush() 并改用该版本。 应该注意的是,一些程序检测到一个 tty 并且在写入一个 tty 时比其他目的地(例如文件或管道)做更少的缓冲。即使输出不会发送到终端,您也可以创建一个伪 tty 以减少缓冲。 @EJP +1 for the "fflush() in the C program" 这是我寻找 8 小时终于开始工作的解决方案。仍然想知道它为什么有效?有什么诀窍?以上是关于为啥 InputStreamReader 不实时读取进程的输出?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 InputStreamReader 从 jar 读取时会抛出 NPE?
Java基础InputStream InputStreamReader和BufferedReader