请看以下四个程序。在Windows下使用Freepascal构建它们并运行,将输出重定向到任何文件,并注意它将花费的时间。
我的结果是:所有程序运行的时间大约相同(大约6秒),尽管第四个程序输出的字节数是100倍。这意味着第四个程序的每个输出字节的运行速度比其他字节的运行速度快得多。
对于第二个程序,缓慢的原因很明显:flush
调用。对于第三个程序,原因并不那么明显,但可以合理地假设每次调用writeln
到stdout都会隐式刷新输出缓冲区。
然而,目前尚不清楚为什么第一个程序比第四个程序慢得多。但是,添加flush(output);
(参见程序2)并不会改变时序这一事实似乎意味着即使在每write
之后FPC也会刷新输出缓冲区,这可以解释所有行为。仅当输出为stdout,甚至重定向时才会发生这种情况;如果我使用assign / rewrite显式地输出到特定文件,那么没有flush的程序运行速度比使用flush的程序快得多 - 正如应该的那样。
在Linux下,运行时间为0.01秒,0.65秒,0.01秒,0.30秒(输出为100倍)。这里显然flush()减慢程序,所以在Linux下FPC似乎不会每次刷新stdout。
我曾试图谷歌FPC是否真的在每个输出上刷新stdout缓冲区(无论是write
还是writeln
),但是除了示例程序中的注释之外,没有找到任何信息来自flush函数文档http://www.freepascal.org/docs-html/rtl/system/flush.html,评论中提到了writeln
到'输出'总是导致刷新[而不是write
]。但是,这个例子既没有在Windows下产生预期的输出,也没有在Linux下产生。实际上,输出似乎在Windows下的每次写入和写入之后刷新,重定向或不重定向,并且在输出未重定向时也在Linux下刷新。在具有重定向输出的Linux下,似乎根本没有隐式刷新。
所以,我的问题是:
write
还是writeln
)之后,无论输出是否重定向到文件,FPC都会刷新输出缓冲区吗?我的系统是在Kubuntu 14.04下的VirtualBox下使用FPC 2.6.4的Windows XP,以及使用FPC 2.6.2的Kubuntu 14.04本身。我没有机会尝试在真正的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.
答案 0 :(得分:7)
要防止刷新Stdout,请将以下代码段插入您的程序:
// Textrec is defined in sysutils
uses
sysutils;
// ...
// disabled flushing after each write(ln) on Output, do this at the start of the program
Textrec(Output).FlushFunc:=nil;
但请注意,这意味着在程序结束之前可能无法完成writelns。
您甚至可以通过增加stdout的输出缓冲区来进一步加速程序:
// define buffer
var
buf : array[1..100000] of byte;
// ...
// install buffer, do this at the start of the program
SetTextBuf(Output,buf,sizeof(buf));