【发布时间】:2014-11-15 17:54:10
【问题描述】:
请看以下四个程序。在 Windows 下使用 Freepascal 构建它们并运行,将输出重定向到任何文件,并注意它所花费的时间。
我的结果是:所有程序运行的时间大致相同(大约 6 秒),尽管第四个程序的输出字节数增加了 100 倍。这意味着第四个程序每字节输出的运行速度比其他树快得多。
对于第二个程序,缓慢的原因很明显:flush 调用。对于第三个程序,原因并不那么明显,但可以合理地假设每次调用 writeln 到 stdout 都会隐式刷新输出缓冲区。
但是,尚不清楚为什么第一个程序比第四个慢。然而,添加flush(output);(见程序 2)并没有太大改变时间的事实似乎意味着即使在每个write 之后 FPC 也会刷新输出缓冲区,这可以解释所有行为。仅当输出到标准输出时才会发生这种情况,甚至重定向;如果我使用分配/重写显式输出到特定文件,则没有刷新的程序运行速度比使用刷新的程序快得多——正如预期的那样。
Linux 下运行时间分别为 0.01s、0.65s、0.01s、0.30s(输出放大 100 倍)。这里显然flush()会减慢程序的速度,所以在Linux下FPC似乎不会每次都刷新stdout。
我试图用谷歌搜索 FPC 是否真的在每个输出上刷新标准输出缓冲区(无论是 write 还是 writeln),但除了 http://www.freepascal.org/docs-html/rtl/system/flush.html 的刷新函数文档中的示例程序中的注释外,没有找到任何信息,评论提到writeln 到“输出”总是会导致刷新[而不是write]。但是,那里的示例在 Windows 下和 Linux 下都没有产生预期的输出。事实上,在 Windows 下,无论是否重定向,每次 write 和 writeln 后,输出似乎都会被刷新,而在 Linux 下,当输出未重定向时也是如此。在具有重定向输出的 Linux 下,似乎根本没有隐式刷新。
所以,我的问题是:
- FPC 是否在每次输出后刷新输出缓冲区,无论是
write还是writeln,在 Windows 上是否将输出重定向到文件? - 如果是,那么有什么方法可以关闭它(某些编译器指令或解决方法)?我仍然需要将输出保留到标准输出,这样如果我在没有任何重定向的情况下启动程序,它将向控制台输出文本。 (我知道由于缓冲,我可能会看到它在奇怪的时间出现,这不是问题。)
- 如果不是,那为什么第一个程序比第四个运行得慢很多?
我的系统是 Windows XP,在 Kubuntu 14.04 下的 VirtualBox 下带有 FPC 2.6.4,而 Kubuntu 14.04 本身带有 FPC 2.6.2。我没有机会尝试在真正的 Windows 机器上运行它,但我有理由相信那里的情况是一样的。
节目:
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do
write('!');
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do begin
write('!');
flush(output);
end;
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do
writeln('!');
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 10000 do begin
s:='';
for i:=1 to 100 do
s:=s+'!';
write(s);
end;
end.
【问题讨论】:
-
1.这是真的。举个例子:
writeln('please type this'); answer := readln;如果 writeln 没有刷新,那么最终用户就在黑色控制台前。即使 i/o 没有被重定向,这也会追加。 -
@user3661500,我理解这一点,并且确实希望看到
writeln刷新缓冲区,这就是我的第三个程序的内容。然而,令我惊讶的是,即使write也会刷新它。
标签: windows stdout flush freepascal