Delphi中三種延時方法及其定時精度分析

Delphi中三種延時方法及其定時精度分析     選擇自 listenwind 的 Blog 
關鍵字   Delphi中三種延時方法及其定時精度分析
出處   
 
   在Delphi中,通常可以用以下三種方法來實現程序的延時,即TTtimer控件,Sleep函數,GetTickCount函數。但是其精度是各不相同的。

一、三種方法的簡單介紹

1)TTtimer控件

  TTtimer控件的實質是調用Windows API定時函數SetTimer和KillTimer來實現的,並簡化了對WM_TIMER 消息的處理過程。通過設置OnTimer事件和Interval屬性,我們可以很方便的產生一些簡單的定時事件。

2)Sleep函數

  Sleep函數用來使程序的執行延時給定的時間值。Sleep的調用形式爲Sleep(milliseconds),暫停當前的進程milliseconds毫秒。Sleep的實現方法其實也是調用Windows API的Sleep函數。例如:

sleep(1000);        //延遲1000毫秒

Sleep會引起程序停滯,如果你延遲的時間較長的話,你的程序將不能夠響應延時期間的發生的其他消息,所以程序看起來好像暫時死機。

3)GetTickCount函數

  在主程序中延時,爲了達到延時和響應消息這兩個目的,GetTickCount()構成的循環就是一種廣爲流傳的方法。例如:

procedure Delay(MSecs: Longint);
//延時函數,MSecs單位爲毫秒(千分之1秒)
var
  FirstTickCount, Now: Longint;
begin
  FirstTickCount := GetTickCount();
  repeat
    Application.ProcessMessages;
    Now := GetTickCount();
  until (Now - FirstTickCount >= MSecs) or (Now < FirstTickCount);
end;

二、高精度的微妙級性能計數器(high-resolution performance counter)介紹

  爲了比較以上方法的精度,首先需要找到一個參考的定時器。在這裏,我提供了兩個參考的定時器。一是用單片機每隔1.024ms產生一個實時中斷RTI,作爲計數器;二是選用了一個高精度的微妙級性能計數器(參見: http://msdn.microsoft.com/msdnmag/issues/04/03/HighResolutionTimer/default.aspx ,或者 http://community.csdn.net/Expert/FAQ/FAQ_Index.asp?id=200249

1)計數器的Delphi源代碼


A  high-precision  counter/timer.  Retrieves  time  differences 
                               downto  microsec. 
Quick  Reference: 
                               THPCounter  inherits  from  TComponent. 
 
                               Key-Methods: 
                                   Start:        Starts  the  counter.  Place  this  call  just  before  the 
                                                       code  you  want  to  measure. 
 
                                   Read:          Reads  the  counter  as  a  string.  Place  this  call  just 
                                                       after  the  code  you  want  to  measure. 
 
                                   ReadInt:    Reads  the  counter  as  an  Int64.  Place  this  call  just 
                                                       after  the  code  you  want  to  measure. 
-------------------------------------------------------------------------------- 

unit  HPCounter; 
 
interface 
 
uses 
   SysUtils,  WinTypes,  WinProcs,  Messages,  Classes,  Graphics,  Controls, 
   Forms,  Dialogs,  StdCtrls,  ExtCtrls; 
 
type 
   TInt64  =  TLargeInteger; 
   THPCounter  =  class(TComponent) 
private 
   Frequency:  TLargeInteger; 
   lpPerformanceCount1:  TLargeInteger; 
   lpPerformanceCount2:  TLargeInteger; 
   fAbout:  string; 
   procedure  SetAbout(Value:  string); 
   {  Private  declarations  } 
public 
   constructor  Create(AOwner:  TComponent);  override; 
   destructor  Destroy;  override; 
   procedure  Start; 
   function  Read:  string; 
   function  ReadInt:  TLargeInteger; 
   {  Private  declarations  } 
published 
   property  About:  string  read  fAbout  write  SetAbout; 
   {  Published  declarations  } 
end; 
 
 
procedure  Register; 
 
implementation 
 
procedure  Register; 
begin 
   RegisterComponents('MAs  Prod.',  [THPCounter]); 
end; 
 
constructor  THPCounter.Create(AOwner:  TComponent); 
begin 
   inherited  Create(AOwner); 
   fAbout:=  'Version  1.1,  2000&reg;  Mats  Asplund,  EMail:  [email protected],  Site:  http://go.to/masdp'
end; 
 
destructor  THPCounter.Destroy; 
begin 
   inherited  Destroy; 
end; 
 
function  THPCounter.Read:  string; 
begin 
   QueryPerformanceCounter(TInt64((@lpPerformanceCount2)^)); 
   QueryPerformanceFrequency(TInt64((@Frequency)^)); 
   Result:=IntToStr(Round(1000000  *  (lpPerformanceCount2  - 
                                             lpPerformanceCount1)  /  Frequency)); 
end; 
 
function  THPCounter.ReadInt:  TLargeInteger; 
begin 
   QueryPerformanceCounter(TInt64((@lpPerformanceCount2)^)); 
   QueryPerformanceFrequency(TInt64((@Frequency)^)); 
   Result:=Round(1000000  *  (lpPerformanceCount2  - 
                                             lpPerformanceCount1)  /  Frequency); 
end; 
 
procedure  THPCounter.SetAbout(Value:  string); 
begin 
   Exit; 
end; 
 
procedure  THPCounter.Start; 
begin 
   QueryPerformanceCounter(TInt64((@lpPerformanceCount1)^)); 
end; 
 
end. 

2)使用方法: 
unit  Unit1; 
 
interface 
 
uses 
   Windows,  Messages,  SysUtils,  Classes,  Graphics,  Controls,  Forms,  Dialogs, 
   HPCounter,  StdCtrls; 
 
type 
   TForm1  =  class(TForm) 
       Button1:  TButton; 
       Edit1:  TEdit; 
       Label1:  TLabel; 
       Label2:  TLabel; 
       procedure  Button1Click(Sender:  TObject); 
   private 
       {  Private  declarations  } 
   public 
       {  Public  declarations  } 
   end; 
 
var 
   Form1:  TForm1; 
 
implementation 
 
{$R  *.DFM} 
 
procedure  TForm1.Button1Click(Sender:  TObject); 
begin 
   Edit1.Text:=  ''; 
   Application.ProcessMessages; 
   with  THPCounter.Create(Self)  do 
       begin 
           Start; 
           //  Place  code  to  measure  here 
           Sleep(1000); 
           //  Place  code  to  measure  here 
           Edit1.Text:=Read; 
           Free; 
       end; 
end; 
 
end.

二、三種方法的精度比較

  爲了比較,採用以上3種方法,分別設置延時時間爲1ms、2ms、5ms、10ms、20ms、50ms、100ms、200ms、500ms、1000ms,循環次數爲5次,得到實際的延時時間。

1)TTtimer控件

                       實際延時時間(ms)
1ms: 8.012   21.551  6.875   21.647  9.809
2ms: 9.957   20.675  14.671  11.903  20.551
5ms: 9.952   20.605  9.924   20.705  12.682
10ms:14.852  9.96    21.547  9.82    20.634
20ms:27.512  34.291  26.427  31.244  30.398
50ms:61.196  61.307  64.027  62.048  63.059
100ms:102.495 108.408 112.318 110.322 102.531
200ms:193.955 202.135 207.016 205.082 202.194
500ms:496.659 500.534 503.398 495.551 500.394
1000ms:999.699 1003.576 993.698 1004.443 995.625

2)Sleep函數

1ms: 1.895   1.895   1.896   1.897   1.898
2ms: 2.868   2.874   2.852   2.872   2.869
5ms: 5.8     5.797   5.79    5.79    5.791
10ms:10.675  10.683  10.611  10.669  10.67
20ms:20.404  20.434  20.447  20.477  20.368
50ms:50.67   50.691  50.69   50.682  50.671
100ms:100.515 100.469 100.484 100.481 100.484
200ms:200.101 200.126 199.892 200.066 200.108
500ms:499.961 499.961 499.958 499.961 499.96
1000ms:1000.034 1000.04 1000.03 1000.018 1000.029

3)GetTickCount函數

1ms: 15.54   15.596  15.527  15.566  15.838
2ms: 15.561  15.563  15.603  15.477  15.571
5ms: 15.519  15.549  15.569  15.666  15.394
10ms:15.558  15.561  15.522  15.568  15.518
20ms:31.186  31.137  31.17   31.17   31.19
50ms:62.445  62.4    63.893  60.88   62.404
100ms:109.276 109.298 109.273 109.28  109.28
200ms:203.027 203.084 203.021 203.027 203.046
500ms:499.959 499.961 499.963 499.967 499.965
1000ms:1000.023 1000.022 1000.026 1000.029 1000.021

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章