Java 程序在将标准输出重定向到文件时速度变慢



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

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

如果我使用标准输出重定向到文件来运行它,那么这需要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( "%1000dn", 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 看到我重定向到文件时,它会做什么呢?

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

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( "%1000dn", 1234 );
}
}
}

编辑

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

这意味着printf( '%dn', 1 )被写成 2 个不同的写,每个写一个字节......

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

最新更新