>我有一个简单的独立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 个不同的写,每个写一个字节......
至于您的问题:
通过管道(|
(重定向是在内存中完成的,因此不涉及磁盘写入...