Delphi中准确记录程序执行时间

知道如何在你的Windows和跨平台应用程序中获得一个操作的确切执行时间的信息,在各种情况下都是有用的。例如,当你需要向用户展示一个长的操作的执行时间时,它可能是必要的(顺便说一下,在这种情况下,很少需要高精确度)。或者在你优化软件的时候,你可能需要知道执行一个特定操作所需的确切时间。一个高精度和可靠的定时器可以成为其中的关键部分,它可以确定程序中最具挑战性的地方,在那里它 "卡 "了很长一段时间。通常,后一种情况是典型的,当你在处理使用和处理大量数据的程序时,操作速度可能不是最优先的,但仍然是应用程序的最关键要求之一。

了解你的可执行代码中最快速和最慢的部分是软件度量的概念的一部分--测量程序执行。全面了解这个指标和其他指标,如最大内存使用量、网络流量吞吐量、数据操作等,可以让你规划未来的发展,并找出有改进空间的地方。

有几种方法可以检查Delphi中操作的执行时间。 在这篇文章中,我们将研究几种可能的方法。

一、如何使用Now()函数为我的应用程序的某些区域计时?

最简单但最不准确的方法是使用System.SysUtils模块中的Now()函数来测量在Delphi中执行一个操作所需的时间。

源代码可能看起来如下。

uses System.DateUtils;
....
var Start, Stop: TDateTime;
    Elapsed: int64;
begin
  Start := Now; //mark the start of the operation
  DoSomething;  //execute the operation
  Stop := Now;  //mark the end of the operation
  Elapsed := SecondsBetween(Start, Stop); //time in seconds
end;

你很可能会有以下问题。为什么我们在例子中使用SecondsBetween(),而不是例如MilliSecondsBetween()可以确保更高的准确性?我们依靠官方Delphi帮助中对Now()函数的描述。它是这样说的 "虽然TDateTime值可以代表毫秒,但Now只精确到最近的一秒。" 这意味着,如果你使用Now(),以毫秒的精度来确定时间间隔是没有多大意义的。

二、我如何使用Windows API和GetTickCount()函数为我的应用程序的各个区域计时?

GetTickCount()函数没有参数,它检索的是系统启动后所经过的毫秒数。根据微软的官方文档,GetTickCount()函数的分辨率仅限于系统定时器的分辨率,通常在10到16毫秒之间。如果系统运行时间超过49.7天,毫秒计数器将被重置。

一般来说,使用这个函数的例子与前面的例子类似。

var Start, Stop: cardinal;
  Elapsed: cardinal;
begin
  Start:=GetTickCount; //mark the start of the operation
  DoSomething;//execute the operation
  Stop:=GetTickCount; //mark the end of the operation
  Elapsed:=Stop-Start;//time in milliseconds
end;

因此,通过GetTickCount()函数,我们可以以毫秒级的精度跟踪Delphi中一个操作的执行时间。如果这样的精度不适合你,你需要更精确地测量时间间隔,那么,正在考虑的下一个方法就适合你。

三、如何使用QueryPerformanceCounterQueryPerformanceFrequency函数为应用程序中的函数计时?

QueryPerformanceCounter - 检索性能计数器的当前值,它是一个高分辨率(<1us)的时间戳,可用于时间间隔测量。

QueryPerformanceFrequency - 检索性能计数器的频率。性能计数器的频率在系统启动时是固定的,并且在所有处理器上是一致的。这就是为什么你只需要在应用初始化时请求频率,而且结果可以被缓存。

为了使用这些函数来计算在Delphi中执行任何操作所需的时间间隔,我们需要对源代码进行安排,例如,以下方式。

var iCounterPerSec: TLargeInteger;
    T1, T2: TLargeInteger; //counter value BEFORE and AFTER the operation
begin
  QueryPerformanceFrequency(iCounterPerSec);//determine the frequency of the counter 
  QueryPerformanceCounter(T1); //mark the start of the operation
 
  DoSomething; //execute the operation
 
  QueryPerformanceCounter(T2);//mark the end of the operation
  ShowMessage(FormatFloat('0.0000', (T2 - T1)/iCounterPerSec) + ' сек.');//show  the required number of seconds to complete the operation

end;

你可以按照你的意愿处理获得的T1T2的值,例如,你可以分别显示分钟/秒/毫秒,等等。这取决于你的需要和愿望。在这篇文章中,我展示了在Delphi中使用高分辨率计数器的最简单例子。

四、如何使用Delphi.System.Diagnostics模块的能力为应用程序中的函数计时?如何使用Delphi.System.Diagnostics模块的能力来为应用程序中的功能计时?

System.Diagnostics模块在很早以前就被引入Delphi。该模块只提供一个记录--TStopwatch。它本质上是一个方便的 "包装器",用于在你的跨平台应用程序中使用高分辨率的定时器。TStopwatch使用依赖于操作系统的功能来访问高分辨率的计时器,如果它们是可用的。如果操作系统中没有高分辨率的计时器,就会使用普通的计时器。

尽管TStopwatch是一个记录,你仍然需要调用CreateStartNew方法来正确使用它。

TStopwatch的描述如下。

TStopwatch = record
  strict private
    class var FFrequency: Int64;
    class var FIsHighResolution: Boolean;
    class var TickFrequency: Double;
  strict private
    FElapsed: Int64;
    FRunning: Boolean;
    FStartTimeStamp: Int64;
    function GetElapsed: TTimeSpan;
    function GetElapsedDateTimeTicks: Int64;
    function GetElapsedMilliseconds: Int64;
    function GetElapsedTicks: Int64;
    class procedure InitStopwatchType; static;
  public
    class function Create: TStopwatch; static;
    class function GetTimeStamp: Int64; static;
    procedure Reset;
    procedure Start;
    class function StartNew: TStopwatch; static;
    procedure Stop;
    property Elapsed: TTimeSpan read GetElapsed;
    property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds;
    property ElapsedTicks: Int64 read GetElapsedTicks;
    class property Frequency: Int64 read FFrequency;
    class property IsHighResolution: Boolean read FIsHighResolution;
    property IsRunning: Boolean read FRunning;
  end;
  • IsHighResolution属性指定了定时器是否基于高分辨率的性能计数器。

  • Start()方法开始测量经过的时间。

  • Stop()方法停止测量经过的时间。

  • ElapsedMilliseconds 属性获取以毫秒为单位的总耗时。

  • Elapsed属性以TTimeSpan的形式获得经过的时间。

五、在应用程序中,是否有一个使用TStopWatch为功能计时的例子?

使用TStopwatch的功能是非常简单的。例如,可以按以下方式进行。

uses System.Diagnostics;
...
var SW: TStopwatch;
begin
  SW:=TStopwatch.StartNew;
  SW.Start;
 
  DoSomething;
 
  SW.Stop;
  ShowMessage(SW.Elapsed.TotalMinutes.ToString);
end;

在上面的例子中,我们使用了TStopwatch,并显示了执行一个特定操作所需的分钟数(含小数部分)。一般来说,使用TStopwatch.Elapsed,你可以显示任何数值,只受限于TTimeSpan的特性。

六、在应用程序中,记录函数执行时间的最佳方式是什么?

要测量Delphi中一个操作的确切执行时间,首先需要决定什么精度适合你。

  • 如果第二精度足够,你可以使用通常的、著名的Now()函数。是的,精度是最低的,但是,另一方面,这种方法是绝对简单的。

  • 如果你想达到毫秒级的精度,使用GetTickCount()它简单而可靠,但前提是你不打算测量一个将超过49.7天的时间间隔。

  • 如果你需要使用最精确的方法来测量执行时间--在一个Windows应用程序中,那么我们建议使用QueryPerformanceCounter()QueryPerformanceFrequency()函数的组合。

  • 最后,最方便的方法是使用System.Diagnostics模块中的TStopwatch。这是最适合跨平台应用程序的,因为它可以在任何地方工作,包括Windows、Linux、iOS、AndroidmacOS

这篇文章是由Embarcadero技术合作伙伴 Softacom撰写的。 Softacom公司专门从事以Delphi为中心的各种软件开发工作。在 Softacom网站上阅读更多关于他们的服务。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值