我有一个简单的独立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看到我重定向到文件时,它正在做什么?
答案 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个不同的写入,每个写入一个字节......
关于你的问题:
通过管道(|
)重定向在内存中完成,因此不涉及磁盘写入...