Delphi中三种延时方法及其定时精度分析

Delphi中三种延时方法及其定时精度分析

选择自 listenwind 的 Blog

关键字 Delphi中三种延时方法及其定时精度分析
  在Delphi中,通常可以用以下三种方法来实现程序的延时,即TTtimer控件,Sleep函数,GetTickCount函数。但是其精度是各不相同的。
一、三种方法的简单介绍
1)TTtimer控件
  TTtimer控件的实质是调用WindowsAPI定时函数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?? Mats Asplund, EMail: masprod@telia.com, 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

  可见,相对而言,Sleep的精度最高,尤其是在10ms以内的延时,只有sleep函数才能够做到。TTimer控件的定时精度最差,而且稳定性不好,波动很大。GetTickCount函数所能实现的最短延时为15ms左右,稳定性相对TTimer要好一些。

 

 

/延时函数,MSecs单位为毫秒(千分之1秒
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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值