I am trying to use ProcessBuilder to run some external commands, like ifstat or vmstat in Linux.
Such kinds of commands support custom sampling intervals. If I add a sample interval to the external command, for example, ifstat 20, then the command will output like this:
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
after 20 seconds
41.29 1.06 0.36 0.00 0.00 0.00 0.00 0.00
after another 20 seconds
16.67 0.58 0.38 0.00 0.00 0.00 0.00 0.00
However, when I am running the command using my Java code, the first part of the output will be read after 20 seconds, like this:
Start running "ifstat 20"
after 20 seconds
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
When I use a NIO server to run the command and use SocketChannel to send the output to the client, the problem is even more severe… (my client needs to wait another 20 seconds to get the output from server after server shows the first output which is 20 seconds after the process start)
And I noticed that the length of the delay of outputing is related to the interval I set to the command.
So why doesn’t the ISR read the output in real time?
A simple test code snippet to demo my question:
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) {
}
}
Update:
As Peter’s comment, this is not a problem related to Java. It is a piping delay.
But I still don’t understand, why vmstat 20 | cat doesn’t have this delay, while ifstat 20 | cat will delay to show the heads?
It does.
It is the output of the process that is delayed. STDIO does buffering, which varies according as stout is or isn’t a terminal.