当前位置: 首页 > news >正文

system_clock::now()和time()时间函数混用带来的踩坑经历

文章目录

  • 前言
  • 时间函数混用
  • 测试的例子
  • 再加一个时间函数
  • 总结

前言

时间是一个可怕的东西,听说能用来杀猪。在编程世界中,时间也控制着一个维度,常常伴随着程序运行而流逝,有时也会影响着程序的运行的逻辑,所以在程序中处理时间时还是要仔细一些,最近连续踩坑,总结一下给自己提个醒,有些逻辑还是需要抱着怀疑的态度去看待。

时间函数混用

我们在写一个小程序时基本不会去混用时间函数,比如只用 time(NULL) 去控制时间,或者只使用 chrono::system_clock::now() 来记录时间消耗,关于 chrono 的用法,之前简单总结过,可传送至 C++11中的时间库std::chrono。

但是当程序变得复杂起来,这个时间函数混用的高压线还是有可能触碰到的,当程序逻辑对时间要求越发精确时,混用所带来的后果将越发严重。在此记录一个结果:连续调用 time(NULL)chrono::system_clock::now() 两个函数得到的时间戳可能是不同的。

可能你会说,函数是先后调用的,肯定是不同的,后面的函数调用时的时间戳要比前面的大,但事实却是两个函数所取得的时间戳大小不确定,可能是第一个函数的时间戳比较大,也可能是第二个时间戳更大一些。

测试的例子

下面展示一段代码,先后调用两个时间函数,打印所获得的时间戳,可以看看有什么特点:

#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#include <iostream>
#include <chrono>
using namespace std;

int main()
{
    int64_t t1, t2;
    while (true) {
        t1 = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
        t2 = time(0);

        if (t1/1000 != t2) cout << t1 << " " << t2 << endl;
    }

    return 0;
}

编译运行结果如下:

albert@home-pc:testtime$ g++ testtime.cpp -std=c++11
albert@home-pc:testtime$ ./a.out
1607779917993 1607779918
1607779957999 1607779958
1607780080001 1607780079
1607780103001 1607780102
1607780150001 1607780149
1607780202001 1607780201
1607780327999 1607780328
1607780440001 1607780439
...

运行之后很快就出现了一些不一致,对比可以发现,两个时间戳一个是毫秒,一个是秒,同时把单位转化成秒来比较时,两者大小不定,从仅有的这几行结果来看,最大的误差是7毫秒。

再加一个时间函数

除了上面提到的两个函数,还有一个 gettimeofday() 函数也是在获取时间时常常使用的,把它也放到测试函数中对比一下:

#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#include <iostream>
#include <chrono>
using namespace std;

int main()
{
    int64_t t1, t2, t = 0;
    struct timeval tv;
    while (true) {
        t1 = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
        t2 = time(0);
        gettimeofday(&tv, NULL);

        if (t1/1000 != t2 || t2 != tv.tv_sec)
            if (t != t1) cout << t1 << " " << t2 << " " << tv.tv_sec << "," << tv.tv_usec << endl;

        t = t1;
    }
    return 0;
}

运行后查看结果:

albert@home-pc:testtime$ g++ testtime.cpp --std=c++11
albert@home-pc:testtime$ ./a.out
1607876993000 1607876992 1607876993,2
1607876994000 1607876993 1607876994,3
1607876995000 1607876994 1607876995,3
1607876996000 1607876995 1607876996,2
1607876997000 1607876996 1607876997,1
1607876998000 1607876997 1607876998,2
1607876999000 1607876998 1607876999,2
1607877000000 1607876999 1607877000,3
1607877001000 1607877000 1607877001,1
1607877002000 1607877001 1607877002,3
1607877003000 1607877002 1607877003,2
1607877004000 1607877003 1607877004,2
1607877005000 1607877004 1607877005,1
1607877006000 1607877005 1607877006,3
1607877007000 1607877006 1607877007,2
1607877008000 1607877007 1607877008,11
1607877009000 1607877008 1607877009,3
...

真是各不相同,这要是在发射火箭时混用两个时间函数,那估计探月卫星就凉凉了……

总结

  • 常用来获取时间戳的函数有 time()chrono::system_clock::now()gettimeofday()
  • 时间函数不要混用,否则会给精密计算带来巨大的麻烦,造成计算结果的不可控
  • 测试发现 chrono::system_clock::now()gettimeofday() 时间非常接近,有微秒级别的误差,但也不建议混用

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

有的人走了只留下一撮灰烬,有的人离开却千古留名,但在时间长河中就是那么一瞬,意义何在,有差吗?

相关文章:

  • 2020年终总结!新的起航,新的征程
  • 在比较Linux和Windows命令差异时意外发现了Windows Terminal
  • 记一次解决Intel 9462无线网卡的笔记本安装Ubuntu16.04后无法连接WIFI问题的艰难历程
  • 启用make多任务参数让构建过程加速完成
  • C++中一些方便的算法函数和吃不够的语法糖
  • C/C++中string和int相互转换的常用方法
  • TCP/IP协议簇中的子网掩码有什么作用
  • Go环境配置时遇到的GOPATH路径以及包管理问题
  • linux环境下的mount命令到底有什么玄机
  • Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了
  • 解决git命令会将结果输出到单独窗口必须按q才能退出的问题
  • C++中反向遍历map时怎样删除元素
  • C++中常见的字符判断与处理方法
  • 写给自己的KMP——C++版本
  • C++中一些可以在偷懒时直接使用的函数
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【Amaple教程】5. 插件
  • golang 发送GET和POST示例
  • JS字符串转数字方法总结
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • learning koa2.x
  • Linux快速复制或删除大量小文件
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • Terraform入门 - 3. 变更基础设施
  • VuePress 静态网站生成
  • XForms - 更强大的Form
  • 对JS继承的一点思考
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 解析带emoji和链接的聊天系统消息
  • 那些被忽略的 JavaScript 数组方法细节
  • 配置 PM2 实现代码自动发布
  • 设计模式 开闭原则
  • 设计模式(12)迭代器模式(讲解+应用)
  • 协程
  • 正则表达式
  • Java数据解析之JSON
  • 从如何停掉 Promise 链说起
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #ifdef 的技巧用法
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #在 README.md 中生成项目目录结构
  • (HAL库版)freeRTOS移植STMF103
  • (vue)页面文件上传获取:action地址
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (二十四)Flask之flask-session组件
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (力扣)循环队列的实现与详解(C语言)
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (循环依赖问题)学习spring的第九天
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)甲方乙方——赵民谈找工作
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程