首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在一个长期的过程中显示GUI进度?

如何在一个长期的过程中显示GUI进度?
EN

Stack Overflow用户
提问于 2014-08-28 11:28:37
回答 3查看 896关注 0票数 1

我需要处理一些数据,每5-10秒显示一次进度(我以%显示进度,但我也更新了一些图表)。我想在没有多线程的情况下完成这个任务。循环可能会很大。它可以从数百万开始,甚至高达数十亿。

我可以使用GetTickCount:

代码语言:javascript
复制
const 
  RefreshEvery= 5000;

for x:= 1 to 10000000000 do
 if GetTickCount-OldTime> RefreshEvery then
 begin
   OldTime:= GetTickCount;
   if Assigned(FProgress) then FProgress(Self);
 end; 

但是调用循环中的GetTickCount执行数十亿次.

对最有效的方法有什么想法吗?

为什么没有多线程呢?

这是一个很大的应用程序,有一个故障的GUI进度模块。我想修复这个问题,重新打包并交付它,而不需要对它进行大的更改,这就需要再次进行密集的测试。多线程?很好,但稍后..。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-28 12:10:41

您的问题似乎是确定一种有效的方法来评估发布进度更新的间隔。如果你对线程化的方法死心塌地,那么你所做的一切都是好的--没有太多的改进之处。事实上,确定更新间隔的效率在线程代码中也同样重要,所以无论线程还是非线程,问题都是一样的。

您似乎对FProgress(self)的内容(即:如何执行状态更新)没有任何问题,这似乎也不是关于“解冻”GUI的问题,因此我将不讨论这些问题。

你的选择是

  • GetTickCount --基于时间的更新
  • 基于循环变量的if x mod 1000 = 0更新
  • (类似于) if x shl 22 = 0 --和上面一样,但是没有除法的模式1024很狡猾。
  • Per @LURD,您也可以使用类似的if i and $3FF = 0来实现类似的性能。

如果您的循环中有任何内容,那么它们的性能几乎是相同的。测试:

代码语言:javascript
复制
program Project1;

uses Windows, SysUtils;

{$APPTYPE CONSOLE}    

var 
  i : integer;
  t0 : cardinal;
begin
  t0 := GetTickCount;
  for i := 0 to 1000000000 do begin
    if t0 - GetTickCount > 1000 then;
  end;
  t0 := GetTickCount - t0;
  WriteLn('GetTickCount : ' + IntToStr(t0));

  t0 := GetTickCount;
  for i := 0 to 1000000000 do begin
    if i mod 1000 = 0 then;
  end;
  t0 := GetTickCount - t0;
  WriteLn('i mod 1000 : ' + IntToStr(t0));

  t0 := GetTickCount;
  for i := 0 to 1000000000 do begin
    if i shl 22 = 0 then;
  end;
  t0 := GetTickCount - t0;
  WriteLn('i shl 22 : ' + IntToStr(t0));

  ReadLn;
end.

生产输出(为我)

代码语言:javascript
复制
 GetTickCount : 3978   
 i mod 1000 :   3386   
 i shl 22 :     2184

最后一个选项大约是性能的两倍,但是如果您的循环正在做任何实质性的事情,您可能不会注意到任何不同之处。

附录:

如果您需要满足自己的需要,那么位移法是一种准确的方法:

代码语言:javascript
复制
program Project1;

uses SysUtils;

{$APPTYPE CONSOLE}

var
  i : integer;
begin
  for i := 0 to 1000000000 do begin
    if (i shl 22 = 0) <> (i mod 1024 = 0) then
      WriteLn('not the same! : ' + IntToStr(i));
  end;
  WriteLn('complete.');
  ReadLn;
end.

注意,i shl 22并不等于i mod 1024,但是对于相同的i值,它们都是零。

票数 5
EN

Stack Overflow用户

发布于 2014-08-28 12:23:22

如果不想将繁忙的循环移动到后台线程中,至少可以使用后台线程来计时:

代码语言:javascript
复制
type
  TTimerThread = class(TThread)
  protected
    procedure Execute; override;
  public
    class var Flag: Boolean;
  end;

implementation

{ TTimerThread }

procedure TTimerThread.Execute;
begin
  Sleep(5000); // 5 seconds;
  Flag:= True;
end;

并在繁忙的循环中检查/重置TTimerThread.Flag

Update:一个更好的计时器线程,可以立即终止,而不需要等待5秒:

代码语言:javascript
复制
uses
  Windows, Classes;

type
  TimerThread = class(TThread)
  private
    FEvent: THandle;
  protected
    procedure Execute; override;
  public
    class var Flag: Boolean;
    procedure FastTerminate;
  end;

implementation

{ TimerThread }

procedure TimerThread.Execute;
begin
  FEvent:= CreateEvent(nil, True, False, nil);
//  FreeOnTerminate:= True;
  while not Terminated do begin
    if WaitForSingleObject(FEvent, 5000) = WAIT_TIMEOUT then
      Flag:= True
    else
      Terminate;
  end;
  CloseHandle(FEvent);
end;

procedure TimerThread.FastTerminate;
begin
  SetEvent(FEvent);
end;
票数 2
EN

Stack Overflow用户

发布于 2014-08-28 12:12:18

不是最优雅的方法,更确切地说是有点脏,但是它正在工作(与其他答案相反)--它使GUI保持响应性!

如果使用类似于可以根据需要调整的Application.ProcessMessages条件,那么调用x mod 1000 = 0的开销不应该像下面注释的那样庞大。此外,我们不知道“数据处理”的计算强度有多大,而且Application.ProcessMessages的实际影响也不是很小。

代码语言:javascript
复制
procedure TForm2.CancelButtonClick(Sender: TObject);
begin
  FCanceled := true;
end;

procedure TForm2.StartButtonClick(Sender: TObject);
var
  x: Integer;
  timer: TTimer;
begin
  timer := TTimer.Create(self);
  timer.Interval := 5000;
  timer.OnTimer := HandleTimer;
  for x:= 1 to 10000000000 do
  begin
    if (x mod 1000 = 0) then
      Application.ProcessMessages;
    inc(FProgress);
    if FCanceled then
      break;
  end;
  timer.Free;
end;

procedure TForm2.HandleTimer(Sender: TObject);
begin
  Label1.Caption := IntToStr(FProgress);
end;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25547710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档