You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CLOCK_REALTIME的clock_gettime函数计算耗时出现异常值的问题排查

问题分析与解决方案

嘿,这个问题我之前也碰到过,本质上是选了错误的时钟类型加上无符号整数溢出导致的——咱们一步步拆解清楚:

为什么会出现接近2^64纳秒的异常值?

你推测ts.tv_nsec等于-1其实是个误解,真正的根源是**CLOCK_REALTIME时钟的非单调性**:

  • CLOCK_REALTIME对应系统的「墙上时间」,也就是我们日常看到的年月日时分秒。这个时钟是可以被系统主动调整的,比如NTP服务在纠正时间偏差时,可能会把时钟往回拨(比如服务器时间快了几分钟,会直接跳回正确时间)。
  • 当这种时间回拨刚好发生在你记录start_time和stop_time之间时,stop_time会比start_time小。而你用的是uint64_t无符号整数,stop_time - start_time会触发无符号溢出——按照C标准,无符号整数溢出是模2^N的运算,结果就变成了2^64 - (start_time - stop_time),这就是你看到的那些接近2^64纳秒的巨大数值(转换成秒就是约584年)。

这段代码的核心问题

  1. 错误选择了时钟类型:CLOCK_REALTIME不适合用来测量程序运行耗时,因为它会被外部调整,无法保证单调递增。
  2. 未处理时间倒退的情况:无符号整数减法直接溢出,没有做任何边界检查,导致异常输出。

修复方案

方案1:改用单调时钟(推荐)

用CLOCK_MONOTONIC代替CLOCK_REALTIME,这个时钟是从系统启动开始单调递增的,永远不会被回拨,是统计程序耗时的标准选择:

struct timespec ts;
uint64_t start_time;
uint64_t stop_time;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { abort(); }
start_time = ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
/* some computation... */
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { abort(); }
stop_time = ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
printf("%" PRIu64 "\n", (stop_time - start_time + 500000000) / 1000000000);

这个方案从根源上解决了时间回拨的问题,完全适配耗时统计的场景。

方案2:处理时间回拨情况(如果必须用CLOCK_REALTIME)

如果你因为业务需求必须使用CLOCK_REALTIME,那就要检查stop_time是否小于start_time,并做特殊处理:

// ... 前面的时间记录代码不变 ...
uint64_t elapsed;
if (stop_time >= start_time) {
    elapsed = (stop_time - start_time + 500000000) / 1000000000;
} else {
    // 时间回拨了,这里可以设为0或者记录日志
    elapsed = 0;
}
printf("%" PRIu64 "\n", elapsed);

内容的提问来源于stack exchange,提问作者DaBler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:02:44