将stdout重定向到文件时,Java程序会变慢

时间:2018-05-15 13:43:45

标签: java io

我有一个简单的独立Java程序,它使用System.out.println/printf在控制台上输出一些内容。

该程序需要 3秒来读取它的输入并将输出写入控制台。输出大约有1000行,每行200个字符,总计大约200 kB。

如果我使用stdout重定向到运行,则需要超过2分钟才能完成。

操作系统是RedHat Linux,shell是bash。显示相同效果的最小示例:

public class WriteToStdout { // write ~100K to stdout
  public static void main( String[] args ) {
    for ( int i = 0; i < 100; i++ ) {
        System.out.printf( "%1000d\n", 1234 );
    }
}

像这样跑:

/home/gsl> time java WriteToStdout
  ... console output omitted ...
real    0m0.163s
user    0m0.147s
sys     0m0.032s

/home/gsl> time java WriteToStdout > file

real    0m1.045s
user    0m0.151s
sys     0m0.036s

下面的磁盘很快:如果我复制文件或执行yes > file,它会按预期每秒写入100 MB。

如果我将重定向到cat,那么又快了

/home/gsl> time java WriteToStdout | cat > file

real    0m0.152s
user    0m0.146s
sys     0m0.029s

所有单项测试都反复重复,每次运行都会显示相似的时间。

那么当JVM看到我重定向到文件时,它正在做什么?

1 个答案:

答案 0 :(得分:0)

尝试添加一些缓冲,如下所示:

public class WriteToStdout
{

  // write ~100K to stdout
  public static void main( String[] args )
  {
    final PrintStream myout = new PrintStream( new BufferedOutputStream( System.out ) );
    for ( int i = 0; i < 100; i++ )
    {
        myout.printf( "%1000d\n", 1234 );
    }
  }

}

修改

默认情况下PrintStream不进行缓冲,因此每个write操作都直接执行到支持它的流。另一方面,printf分别在它们之间打印每个面具和文本。

这意味着printf( '%d\n', 1 )被写为2个不同的写入,每个写入一个字节......

关于你的问题:
通过管道(|)重定向在内存中完成,因此不涉及磁盘写入...