GCD 中的时间

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;
}
  1. 在 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 中,精确度到微秒。

  2. 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() 的结果进行计算的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值