我有些长,但简单的循环在我的Delphi程序,它可以循环数百万次,并需要几秒钟来执行。循环里面的代码是非常快的,并已进行了优化。因为它是这样做很多时候,它只是需要较长。

e.g:

Screen.Cursor = crHourGlass;
R := FirstRecord;
while R <> nil do begin
  { do something simple with R.Value }
  R := R.NextRecord;
end;
Screen.Cursor := crDefault;

现在我不希望我的程序无响应,所以我想补充的循环内的Application.ProcessMessages。但我也想加入的语句,我的循环减慢尽可能少的。

我下面一个链表,所以我甚至不具有可计数变量,必须添加一个,如果我想的时间间隔。或者,我不得不添加一个计时器,但需要降到最低的时候检查。

我应该如何实现这个最小化真实增加的开销?


结论:

现在,我在做喜欢APZ28的答案的东西。

但它看起来像长期我应该实现某种形式的线程来处理这个的。感谢您指出了这一点,因为我认为这是Application.ProcessMessages做到这一点的唯一途径。

有帮助吗?

解决方案

你能不能把工作循环中的一个线索,以便释放主线程的GUI循环处理。

其他提示

把它下线程,因为它需要锁定的共享资源,如果任何不繁琐。一个好的技巧是有一个计数器,处理循环的#后,呼叫ProcessMessages

var
  LoopCounter: Integer;

LoopCounter := 0;
R := FirstRecord;
while R <> nil do begin
  Inc(LoopCounter);
  if (LoopCounter >= ???) then
  begin
    LoopCounter := 0;
    Application.ProcessMessages;
  end;

  { do something simple with R.Value }
  R := R.NextRecord;
end;

我也愿意投票支持线程或类似Anreas' AsyncCalls 。要禁止用户做过程中所需要的时间的任何非允许的操作,你可以设置一个标志,当程序开始,当它结束(你无论如何都要更新Screen.Cursor)复位。主线程可以在他们的OnUpdate事件检查这个标志,并禁用所有受影响的行动。

最好的办法是到环路进入自己的工作线程,以便主线程没有被阻塞,那么你不需要调用ProcessMessages()在所有。

然而,如果必须在主线程执行循环,则可以使用MsgWaitForMultipleObject()来检测何时调用ProcessMessages(),即:

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if MsgWaitForMultipleObjects(0, nil, False, 0, QS_ALLINPUT) = WAIT_OBJECT_0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

可替换地用的PeekMessage():

var Msg: TMsg;

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

可替换地与GetQueueStatus():

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if GetQueueStatus(QS_ALLINPUT) <> 0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

决定一个问题是,你有答案,无论循环计算之前您的应用程序是否能继续下去。如果不能,那么就没有在应用多点是“有求必应”。如果你想更新进度条什么的,你可以调用.Repaint含进度条每隔一定迭代次数导致进度条重绘控制。

如果应用程序可以继续,至少在一段时间,然后将代码在一个线程是一个好主意。

把循环代码中的一个线索可能是合理的,无论如何,特别是如果你想要做这样的事情可能中止的处理。如果你以前从来没有使用的线程,有一个学习曲线,但对于一个简单的循环,像你描述有很多在网络上的例子。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top