GCD 中的时间
在 GCD 中,定义了一个类型 dispatch_time_t
来表示时间,其单位是纳秒。
typedef uint64_t dispatch_time_t;
从定义可知,其实际是 uint64_t
类型的别名,即一个 64 位的无符号整型值。
另外,GCD 中定义了两个宏来表示当前时间点零以及无穷大的时间。
#define DISPATCH_TIME_NOW (0ull)
#define DISPATCH_TIME_FOREVER (~0ull)
DISPATCH_TIME_FOREVER
的值是对 0 取反,而后强转为 unsigned long long
类型,即 0xFFFFFFFFFFFFFFFF
,该值其实是 uint64_t
所能表示的最大值(typedef unsigned long long uint64_t;
)。
除此之外,还定义了一个枚举值 DISPATCH_WALLTIME_NOW
,类似的,其所表示的值为 0xFFFFFFFFFFFFFFFE
。
enum {
DISPATCH_WALLTIME_NOW DISPATCH_ENUM_API_AVAILABLE
(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = ~1ull,
};
在计算机中数值是以补码的形式进行存储运算的,所以在程序执行过程中,对一个值的取反运算(~),实际是对该值的补码按位取反(包括符号位),而得到的结果仍然是一个补码,其所表示的值需要转化为原码才可知。通常,在计算机中正数进行取反运算后,其所表示的值是原值加 1 后取负值;负数进行取反运算后,其所表示的值是原值加 1 后取绝对值。
用一个等式表示,即 ~a = -(a + 1),如下面两个例子(设值为 4 位二进制位,最高位为符号位):
~1 = -2 ,1 的补码是 0001 ,那么取反后为 1110 ,该值为补码,那么反码就是 1001 ,原码为 1010 ,表示 -2 。
~-2 = 1 ,-2 的原码是 1010 ,反码是 1101 ,补码是 1110 ,那么取反后为 0001 ,该值为补码,那么反码和原码都是 0001 ,表示 1 。
注意取反运算是一种单目运算,而反码是一个概念。
在苹果平台下,时间的计算默认是基于 mach_absolute_time()
函数的。
//获取重启系统后至今的时钟值
uint64_t mach_absolute_time(void);
//包含系统休眠时间
uint64_t mach_continuous_time(void);
这些方法的返回结果是以 Mach 的绝对时间单位计量的值,而这个时间单位是基于 CPU 的,所以要将其转化为现实世界的时间需要进一步计算。
- (void)convertToNanoseconds {
static mach_timebase_info_data_t timebaseInfoS;
uint64_t absoluteTime = mach_absolute_time();
if (timebaseInfoS.denom == 0) {
kern_return_t kern = mach_timebase_info(&timebaseInfoS);
}
uint64_t nanoseconds = absoluteTime * timebaseInfoS.numer / timebaseInfoS.denom;
NSLog(@"%llu",nanoseconds);
}
这里,mach_timebase_info
结构体用来描述系统的时钟信息,而接口中也提供了获取系统时钟信息的函数。
typedef int kern_return_t;
typedef struct mach_timebase_info *mach_timebase_info_t;
typedef struct mach_timebase_info mach_timebase_info_data_t;
kern_return_t mach_timebase_info(mach_timebase_info_t info);
如果是在 OS X 系统下,还可以直接使用系统提供的 AbsoluteToNanoseconds()
函数。
uint64_t GetPIDTimeInNanoseconds(void)
{
uint64_t start;
uint64_t end;
uint64_t elapsed;
Nanoseconds elapsedNano;
start = mach_absolute_time();
(void) getpid();
end = mach_absolute_time();
elapsed = end - start;
elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &elapsed );
return * (uint64_t *) &elapsedNano;
}
-
在 GCD 中,提供了
dispatch_time()
方法来获取时间,这个时间实际是基于某个时间点的纳秒数。dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
-
如果参数 when 传递的是
DISPATCH_TIME_NOW
,那么便会基于mach_absolute_time()
的结果去计算。如常用的任务延迟执行的代码:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ <#code to be executed after a specified delay#> });
-
如果参数 when 传递的是
DISPATCH_WALLTIME_NOW
,那么便会基于gettimeofday()
的结果去计算。#define _STRUCT_TIMEVAL struct timeval typedef long __darwin_time_t; typedef __int32_t __darwin_suseconds_t; _STRUCT_TIMEVAL { __darwin_time_t tv_sec; /* seconds */ __darwin_suseconds_t tv_usec; /* and microseconds */ }; int gettimeofday(struct timeval * __restrict, void * __restrict);
该方法会将从
1970年1月1日
至今的时间保存在结构体timeval
中,精确度到微秒。
-
-
GCD 中同样提供了
dispatch_walltime()
函数来计算基于gettimeofday()
的结果的时间,其结果同样是纳秒数。#define _STRUCT_TIMESPEC struct timespec typedef long __darwin_time_t; _STRUCT_TIMESPEC { __darwin_time_t tv_sec; long tv_nsec; }; dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);
另外,dispatch_time(DISPATCH_WALLTIME_NOW, delta)
同 dispatch_walltime(NULL, delta)
的结果是相同的,都是基于 gettimeofday()
的结果进行计算的。