QElapsedTimer提供了一种快捷的计算流逝时间的方法。它通常被用来计算两个事件或操作之间过去了多久。并且,该类的方法非常类似于我们之前讲过的QTime类的三个计时函数,所以,我们可以很快速的在使用这两个类的代码之间进行移植。但是,不像QTime,QElapsedTimer会尽可能的使用某种单调时钟。这也就意味着,没办法将QElapsedTimer对象转换成人类可读的时间格式。
这个类的典型使用方法就是测量一个耗时操作花了多少时间。最简单的例子如下:
QElapsedTimer timer;
timer.start();
slowOperation1();
qDebug() << "The slow operation took" << timer.elapsed() << "milliseconds";
在这个例子中,我们下定义了一个QElapsedTimer的对象,然后调用它的start() 方法开始计时,完成一个耗时操作后,再调用它的elapsed() 方法,得到耗时操作所花费的具体时间,以毫秒计算。
我们也可以在一个耗时操作完成后,通过elapsed() 函数的返回值来决定下一个耗时操作可以运行的时间。这对于需要在一定的时间周期内完成几个耗时操作来说是至关重要的。比如下面代码所展现的案例:
void executeSlowOperations(int timeout)
{
QElapsedTimer timer;
timer.start();
slowOperation1();
int remainingTime = timeout - timer.elapsed();
if (remainingTime > 0)
slowOperation2(remainingTime);
}
另一个QElapsedTimer的使用案例是,一个具体的操作需要运行一定的时间长度。对于这种需求,QElapsedTimer提供了hasExpired() 函数,这个函数可以判断自从上次调用start() 或restart() 之后,是否过去了多少毫秒。如下代码所示:
void executeOperationsForTime(int ms)
{
QElapsedTimer timer;
timer.start();
while (!timer.hasExpired(ms))
slowOperation1();
}
上面我们说,QElapsedTimer会使用运行平台所支持的某种单调参考时钟。这具有额外的好处,它可以使QElapsedTimer不受系统时间调整的影响,也不受系统时区设置的影响。当然,相对的,这也意味着我们只能把QElapsedTimer的值和那些使用了同样参考时钟的值相比较。特别是,当我们把QElapsedTimer的自从参考点以来的值序列化到某个变量中后,更应该注意这点。并且,不应该把这些值通过网络进行交换或存储到磁盘,因为无法保证接收端的计算机和产生该值的计算机是否使用同一种参考时钟和参考点,也无法保证其自从参考点以来是否发生过重启。但是,我们可以将这些值在运行在同一太机器上的不同进程间进行交换,条件是他们都使用相同的参考时钟。QElapsedTimer在同一台机器上总是使用相同的参考时钟,所以,在一个进程中比较来自另一个进程的QElapsedTimer值是安全的。
注意,QElapsedTimer所使用的时钟类型,有一些是有范围限制的,通常是32-bit,当达到上限时会发生溢出。QElapsedTimer会处理这种情况并提供一致时间。但是,当从QElapsedTimer中提取时间时,同一机器上的两个不同的进程会对实际逝去的时间有不同的理解。
下面,我们就来具体看下QElapsedTimer所使用的集中时钟类型:
- SystemTime
该类型的时钟是唯一一种表示实时时间的时钟,它表示子1970.1.1零点以来的毫秒数。它就相当于C或POSIX中的time() 函数,外加毫秒值。这种时钟类型目前只用于不支持 单调时钟的Unix系统。它也是QElapsedTimer可能使用的唯一一种非单调时钟。
- MonotonicClock
表示系统的单调时钟,表示的是自过去任意时间点以来的毫秒数。这种时钟类型用于支持POSIX时钟类型的Unix系统(_POSIX_MONOTONIC_CLOCK
)。并且,这种时钟类型不会发生溢出。
- TickCounter
这种时钟类型的计时基于系统的或处理器的tick数,然后再乘以一个tick的周期。这种时钟类型用于Windows系统。并且,当高精度的性能计数器可用时,会自动使用PerformanceCounter替代这种时钟类型。TickCounter是唯一一种可能发生溢出的时钟类型。但在Windows Vista 和 Windows server 2008上,由于它们支持扩展的64-bit tick counter,可以避免溢出。
在Windows平台,时钟会在2毫秒,即大约49.7天后溢出。这也意味着两个不同的进程通过乘以2毫秒来计算逝去的时间,得到的结果可能是不同的。当进行这类数值得比较时,我们建议将毫秒的高32位屏蔽掉。
- MachAbsoluteTime
这种时钟类型是基于Mach kernels 表示的绝对时间,例如 OS X。把这种时钟类型和MonotonicClock区分开是因为OS X 和 IOS也是Unix系统,也可能支持一种和Mach绝对 时间具有不同值的POSIX单调时钟。这种时钟是单调的并且不会发生溢出。
- PerformanceCounter
这种时钟类型使用Windows的QueryPerformanceCounter() 和 QueryPerformanceFrequency() 函数访问系统的高精度性能计数器。但因为这种计数器并不是在所有平台上都可用,所以,QElapsedTimer会在该时钟类型不可用时,自动使用TickCounter作为替代。这种时钟类型也是单调的并且不会发生溢出。
搞明白每一种可用的时钟类型和单调性后,我们可以在程序中使用clockType() 函数来获得一个QElapsedTimer对象所使用的底层时钟类型;使用isMonotonic() 函数判断一个QElapsedTimer对象的单调性。
最后,至于该类的使用方式,上面的例子也说的差不多了,最常用的就是start()、restart()、elapsed()这些函数。其他的函数,大家在需要时可以参考Qt帮助文档。