1

我有一个简单的程序,可以根据每行单词的长度对文本文件进行排序,这个程序在我基于 xp 的旧机器上运行没有问题现在我在我的新 win7/intel core i5 机器上运行这个程序,它冻结整个系统并恢复正常完成后它的工作。

我调查了代码并找到了导致冻结的行

就是这条特定的线...

caption := IntToStr(i) + '..' + IntTostr(ii);

我已将其更改为

 caption :=   IntTostr(ii);  //slow rate change

并且没有冻结

然后我把它改成了

caption :=   IntTostr(i);  //fast rate change

它再次冻结

我的程序代码是

 var tword : widestring;
      i,ii,li : integer;
 begin   
     tntlistbox1.items.LoadFromFile('d:\new folder\ch.txt');
     tntlistbox2.items.LoadFromFile('d:\new folder\uy.txt');
     For ii := 15 Downto 1 Do //slow change
      Begin
        For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
        Begin     
          caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
          tword := TntListBox1.items[i];
          LI := Length(tword);
          If lI = ii Then
          Begin             
            tntlistbox3.items.Add(Trim(tntlistbox1.Items[i]));
            tntlistbox4.items.Add(Trim(tntlistbox2.Items[i]));
          End;
        End;
      End;
    end;

知道为什么吗?以及如何解决?我使用德尔福 2007/win32

4

3 回答 3

10

这是否发生在表单上的事件处理程序中?我猜是的。在这种情况下,“标题”在表格的范围内。表单的标题文本不是由 VCL 管理,而是由 Windows 管理,如果您在循环的每次迭代中发送一​​个新的 WM_SETTEXT 消息。

要彻底解释为什么这样做,需要了解我没有的 Windows 内部知识,但如果我猜测一下,我会说它是这样的:

每次您发送带有新标题的 WM_SETTEXT 消息时,Windows 都会检查以确保它与现有标题不同。如果是,它可以立即退出。这就是为什么不频繁的更改(仅使用 的更改ii)不会减慢您的系统速度。但是,如果它确实在每次迭代中都发生了变化,那么 Windows 必须执行某种任务切换才能对其进行更改。

至于为什么这会使整个系统在 Vista 内核(包括 Win7)而不是 XP 下陷入困境,这完全超出了我的专业领域。但是,如果您尝试将此作为某种进度指示器,则有更好的方法,特别是如果此循环与看起来一样紧密。

在紧密循环中处理进度更新的最佳方法是计算迭代次数,并且每 X 次只触发一次。(对于 X 来说,100 或 1000 可能是很好的值,这取决于它运行了多少次以及整个事情需要多快。)这基本上是ii唯一的选择。您也可以尝试在表单上放置一个进度条来衡量进度,而不是通过表单的标题来衡量。

于 2010-06-16T06:24:43.417 回答
2

首先:您忘记了 tntlistbox3.items.BeginUpdate/tntlistbox3.items.EndUpdate 调用(tntlistbox4 相同)。

第二:为什么我长按标题栏我的程序跑得更快?

解决方案(示例):

const
  UpdateInterval = 500; // half a second
var 
  ...
  LastUpdate: Cardinal;
begin   
  ... 
  LastUpdate := GetTickCount + 100000; // forces first update
  For ii := 15 Downto 1 Do //slow change
  Begin
    For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
    Begin     
      if (GetTickCount > (LastUpdate + UpdateInterval)) or
         (GetTickCount < LastUpdate) then
        caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
      ...
    end;
  end;
于 2010-06-16T10:41:56.623 回答
2

更改表单的标题会释放一大堆操作——尤其是在 Vista 和 Win7 下,Aero 处于活动状态。

快速尝试使用 TLabel 代替显示进度。就像是

Label1.caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
Label1.Refresh; // or Repaint

除非您的标签是透明的或在玻璃区域上,否则应该可以解决问题。

最好听从 Mason Wheeler 的建议并使用进度条。由于迭代的总数是15*TntListBox1.items.Count您可以很容易地计算进度值。

于 2010-06-16T07:39:55.850 回答