【问题标题】:Speed Up the Updating of the Status Bar in Delphi加快Delphi中状态栏的更新速度
【发布时间】:2011-02-21 14:52:05
【问题描述】:

在 Delphi 中更新状态栏需要很长时间!

示例:我搜索文件并在状态栏中显示找到和搜索的文件数:

OwnerForm.StatusBar1.SimpleText
     := Format('Searching (%d found in %d files) ...', [NumFound, Total]);

状态栏每更新 200 次,搜索时间就会增加大约 1 秒。

有什么方法可以减少这种过多的开销,但仍然为用户更新状态?

【问题讨论】:

    标签: delphi optimization statusbar


    【解决方案1】:

    不要这么快更新您的状态栏。如果您频繁更新状态以致严重影响您的性能,用户将如何阅读状态?

    此外,我进行了一个小测试,显示它在 100 多毫秒内将状态栏更新了 1000 次。这是在我 5 岁的廉价家用电脑上。

    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Integer;
      a: Cardinal;
    begin
      a := GetTickCount;
      for i := 0 to 1000 do
      begin
        StatusBar1.SimpleText := IntToStr(i);
      end;
      ShowMessage(IntToStr(GetTickCount - a));
    end;
    

    [编辑]

    替代解决方案:

      TForm1 = class(TForm)
        StatusBar1: TStatusBar;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        FLastUpdate: TDateTime;
      public
        procedure UpdateStatus(Status: string);
        procedure ForceStatus(Status: string);
      end;
    
    procedure TForm1.ForceStatus(Status: string);
    begin
      StatusBar1.SimpleText := Status;
      FLastUpdate := Now;
    end;
    
    procedure TForm1.UpdateStatus(Status: string);
    begin
      if MilliSecondsBetween(Now, FLastUpdate) > 500 then
      begin
        StatusBar1.SimpleText := Status;
    
        FLastUpdate := Now;
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Integer;
      a: Cardinal;
    begin
      a := GetTickCount;
      for i := 0 to 1000000 do
      begin
        // unimportant: progress
        UpdateStatus(IntToStr(i));
      end;
      // Important: final state
      ForceStatus(Format('Done in %d milliseconds', [GetTickCount - a]));
    end;
    

    【讨论】:

    • @Golez:显然我必须放慢速度。那么有哪些替代方法可以减缓状态栏的更新速度呢?
    • @Golez:我在一个单独的搜索线程中运行,并且必须将更新同步到状态栏,这样我的程序就会变慢。即便如此,如果您要更新 10,000 次,则需要 10 秒,这是一个很大的开销。
    • 我发布了一个 - 不幸的是 - 集成在 GUI 中的替代方案,因为我认为显示状态并做出决定是 GUI 的事情。我只是读到您正在使用线程。这意味着您仍然必须同步每个更新,仍然会减慢您的速度。您也可以在线程中构建此代码。它可能不是最好的解决方案,但是从工作线程中引用 OwnerForm 并不是最干净的解决方案。 ;) 至少它会提高性能使用户可以阅读状态。赢得胜利。
    • Golez:实际上,FLastUpdate 变量的想法很有效,即使在我的线程中也是如此,而且对 MillisecondsBetween 的简单调用非常好。这就是我一直在寻找的。谢谢。
    • 对于这种类型的更新,我经常使用if i mod 100 = 0 then UpdateStatus
    【解决方案2】:

    当您在单独的线程中运行搜索时,您可以简单地使用 NumFound 和 Total 值更新一些变量。在主线程中,您可以每秒触发一次(或您喜欢的任何更新间隔)来读取此变量并更新状态栏。

    由于 NumFound 和 Total 可能是整数,您可以使用 InterlockedXXX 函数以简单但线程安全的方式更新变量。

    【讨论】:

    • 好主意,但是 Golez 的简单检查可以在线程中正常工作,所以我不必搞乱同步。
    • @lkessler 你已经在搞乱同步了。你会同步。正如您所发现的那样,它的性能特征很差。这种方法是我一直喜欢不加锁的方式。
    • 实际上,只要将整数对齐在 4 字节边界上,您甚至不需要 Interlocked 例程。那时您将拥有的就是所谓的良性种族。
    猜你喜欢
    • 2021-02-27
    • 2011-05-15
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2010-09-09
    • 1970-01-01
    • 2016-11-04
    相关资源
    最近更新 更多