【发布时间】:2018-03-02 11:20:43
【问题描述】:
为什么使用进度条来显示迭代的进度会大大增加相关流程的执行时间? 考虑以下示例:
procedure FileToStringList(FileName: String);
var
fileSource: TStringList;
I: Integer;
begin
fileSource:= TStringList.Create;
try
fileSource.LoadFromFile(FileName);
for I := 0 to fileSource.Count - 1 do
begin
//Code....
end;
finally
fileSource.Free;
end;
end;
如果添加进度条的更新:
procedure FileToStringList(FileName: String);
var
fileSource: TStringList;
I: Integer;
begin
fileSource:= TStringList.Create;
try
fileSource.LoadFromFile(FileName);
ProgressBar.Properties.Max:= fileSource.Count;
for I := 0 to fileSource.Count - 1 do
begin
Application.ProcessMessages;
ProgressBar.Position:= I;
end;
finally
fileSource.Free;
end;
end;
执行迭代过程所需的时间成倍增加。
对一个20万行的文件进行读取测试,不更新进度条,迭代时间约为8秒,但如果激活进度条更新显示迭代进度,这个过程需要几分钟。
一个2700行文件的测试,正常时间2-4秒,但使用进度条,执行时间超过1分钟。
有人可以指出应用程序进程消息的使用是否不正确吗?如果例程在一个单元中或在与进度条相同的窗体上,则结果不会改变。
好的,我可以看到 cmets,但是,有人可以通过示例或链接指出在这些情况下更新进度条的正确方法吗?
【问题讨论】:
-
是的。使用
Application.ProcessMessages很糟糕。但即使它不会,并且处理一行需要 1 毫秒,人眼也不会注意到这一点。 -
如果你有 200,000 行,你就有 200,000 个 processmessages 调用。即使进度条是 1000 像素宽,在它增加 1 个像素之前,您将有 200 次更新,这将是浪费时间。
-
唯一正确的方法是在后台线程中运行您的工作,以线程安全的方式与 GUI 线程通信其状态(例如,通过发送 Windows 消息)。如果在这种情况下工作量太大,如果自上次进度条更新以来已经过去了超过 200 毫秒(例如),您可以将
ProcessMessages替换为进度条更新。 -
另外,您必须将
try放在fileSource:= TStringList.Create;和fileSource.LoadFromFile(FileName);之间。就像现在一样,如果在TStringList.Create中引发异常,则会出现内存损坏或 AV。 -
其实
Application.Processmessages不需要显示Progressbar.Position的变化。
标签: delphi