chrono_CLOCK(二)

news2024/11/27 13:07:56

chrono_CLOCK(二)

文章目录

  • chrono_CLOCK(二)
    • 从测量C++程序运行时间引入
      • C风格
      • C++风格
    • 时钟的成员和源码分析
        • 成员函数
        • 成员变量
      • Clock提供的操作
        • 例子
      • 三个clock
        • 区别
        • 例子
      • 三个clock的精度问题
        • 方式一
        • 方式二

从测量C++程序运行时间引入

C风格

在C程序和C++11以前的C++程序中,测量程序运行时间一般使用clock函数和CLOCKS_PER_SEC常量,定义在<time.h>中。

clock_t是一种能表示时钟周期数的算术类型,在MSVC和GCC中都是long

clock函数返回自一个与程序执行相关的时间起至调用时刻经过的时钟周期数,类型为clock_t。由于起始时间是由实现定义的,clock函数的返回值没有直接的意义,只有两次调用clock的结果之差才有意义。

CLOCKS_PER_SEC表示一秒有多少个时钟周期,在MSVC和GCC中都是1000,即C风格时间测量的精度为1毫秒。如果long的大小是4字节,clock溢出需要24天,一般情况下足够使用。

#include <stdio.h>
#include <time.h>
 
int work()
{
    int sum = 0;
    for (int i = 0; i < 1e8; ++i)
        sum += i * i;
    return sum;
}
 
int main()
{
    clock_t start, finish;
    start = clock();
    volatile int result = work();
    finish = clock();
    printf("%fms\n", (double)(finish - start) / CLOCKS_PER_SEC * 1000);
}

C++风格

从C++11起,C++提供了更加现代的时间工具,定义在<chrono>中,namespace std::chrono下。

chrono库主要定义了三种类型:时钟(clock)、时间点(time point)和时间段(duration)。时钟产生时间点,时间点相减得到时间段,时间点加减时间段得到时间点。由于有auto自动类型推导和运算符重载的存在,我们在使用时很少需要写明与时间相关的变量的类型。

C++标准规定了3种时钟:

  • system_clock,系统范围的挂钟,可以理解为桌面右下角的时钟,这个时钟是可以调节的,因此system_clock的返回值可能不是单调的;

  • steady_clock,稳定的、单调的时钟,不受系统时间调节的影响,因而适合于测量时间间隔,通常测量程序运行时间就用steady_clock

  • high_resolution_clock,可用的最高精度的时钟,可以是上面两个的别名。

  • [ ]

  • 每个时钟都有静态方法now返回当前的时间点,is_steady常量表示时钟是否单调(steady_clock::is_steady一定为true)。system_clock是唯一能与C中time_t互通的时钟。

  • 时钟定义了成员类型period,表示一个时钟周期的时长(以秒为单位)。在MSVC和GCC中,steady_clock::period都是nano,理论上的分辨率为纳秒。

  • 两个时间点相减可以得到时间段,调用其count函数可以获得其数值,这个时间段的类型是由实现定义的。标准还定义了millisecondsseconds等类型,为了得到以我们想要的单位表示的时间段,可以用duration_cast来转换:

#include <iostream>
#include <chrono>
 
int work()
{
    int sum = 0;
    for (int i = 0; i < 1e8; ++i)
        sum += i * i;
    return sum;
}
 
int main()
{
    auto start = std::chrono::steady_clock::now();
    volatile int result = work();
    auto finish = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
    std::cout << duration.count() << "ms" << std::endl;
}
  • 但是这样只能输出整数毫秒,如果想要更精确一点,一种方法是转换成microseconds以后除以1000.0,更优雅地可以自己定义一种时间段类型,如duration<double, milli>,其中double表示这种时间段类型用double来存储时钟周期数量,milli表示时钟周期为1ms。从由整数表示的duration到由浮点数表示的duration的转换可以由duration的构造函数来完成,无需再用duration_cast: (就是 浮点类型自定义deration提高精度 中的例子)

  • 改进的版本

// 自定义时间段类型,提高精度
    void func2()
    {
        auto start = std::chrono::steady_clock::now();
        volatile int result = work();
        auto finish = std::chrono::steady_clock::now();
        using myduration = std::chrono::duration<double, std::milli>;
        myduration md = (finish - start);
        // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
        std::cout << md.count() << "ms" << std::endl;
    }

时钟的成员和源码分析

  • 时钟是持续时间、 time _ point 和获取当前时间的静态函数的组合。

img

 struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime
        using rep                       = long long;
        using period                    = ratio<1, 10'000'000>; // 100 nanoseconds
        using duration                  = _CHRONO duration<rep, period>;
        using time_point                = _CHRONO time_point<system_clock>;
        static constexpr bool is_steady = false;

        _NODISCARD static time_point now() noexcept { // get current time
            return time_point(duration(_Xtime_get_ticks()));
        }

        _NODISCARD static __time64_t to_time_t(const time_point& _Time) noexcept { // convert to __time64_t
            return duration_cast<seconds>(_Time.time_since_epoch()).count();
        }

        _NODISCARD static time_point from_time_t(__time64_t _Tm) noexcept { // convert from __time64_t
            return time_point{seconds{_Tm}};
        }
    };

成员函数

now[静态]返回表示时间中当前点的 std::chrono::time_point (公开静态成员函数)
to_time_t[静态]转换系统时钟时间点为 std::time_t (公开静态成员函数)
from_time_t[静态]转换 std::time_t 到系统时钟时间点 (公开静态成员函数)

成员变量

成员类型定义
rep表示时钟时长中计次数的有符号算术类型
period表示时钟计次周期的 std::ratio 类型,单位为秒
durationstd::chrono::duration<rep, period> ,足以表示负时长
time_pointstd::chrono::time_pointstd::chrono::system_clock

(1)成员函数static time_point now() noexcept; 用于获取系统的当前时间。

(2)由于各种time_point表示方式不同,chrono也提供了相应的转换函数 time_point_cast。

template <class ToDuration, class Clock, class Duration>
  time_point<Clock,ToDuration> time_point_cast (const time_point<Clock,Duration>& tp);

传一个要转换为的精度的duration模板参数和一个要转换的time_point参数(用法见下面综合应用)

(3)其他成员函数:

to_time_t() time_point转换成time_t秒

from_time_t() 从time_t转换成time_point

Clock提供的操作

  • 下图列出了clock提供的类型定义和static成

img

例子

  • 输出当前时间,并且计算当前的时间距离1970年1月1日00:00的毫秒数
#include <iostream>   
#include <chrono>   
#include <ctime>   
using namespace std;  
int main()  
{  
    //定义毫秒级别的时钟类型   
    typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;  
    //获取当前时间点,windows system_clock是100纳秒级别的(不同系统不一样,自己按照介绍的方法测试),所以要转换   
    microClock_type tp = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());  
    //转换为ctime.用于打印显示时间   
    time_t tt = chrono::system_clock::to_time_t(tp);  
    char _time[50];  
    ctime_s(_time,sizeof(_time),&tt);  
    cout << "now time is : " << _time;  
    //计算距离1970-1-1,00:00的时间长度,因为当前时间点定义的精度为毫秒,所以输出的是毫秒   
    cout << "to 1970-1-1,00:00  " << tp.time_since_epoch().count() << "ms" << endl;  
    system("pause");  
    return 0;  
}  

三个clock

  • 标准库提供了三个clock:

    • system_clock

      :它所表现的timepoint将关联至现行系统的即时时钟

      • 这个clock提供便捷函数to_time_t()和from_time_t(),允许我们在timepoint和“C的系统时间类型”timet之间转换,这意味着你可以转换至日历时间
    • **strady_clock:**它保证绝不会被调用,因此当实际时间流逝,其timepoint值绝不会减少,而且这些timepoint相对于真实时间都有稳定的前进速率

    • **high_resolution_clock:**它所表现的是当前系统中带有最短tick周期的clock

  • 这三个clock都支持上面Clock提供的操作

区别

  • steady_clock 是单调的时钟,相当于教练手中的秒表;只会增长,**适合用于记录程序耗时**
  • system_clock 是系统的时钟;因为系统的时钟可以修改;甚至可以网络对时; 所以用系统时间计算时间差可能不准
  • high_resolution_clock 是当前系统能够提供的最高精度的时钟;它也是不可以修改的。相当于 steady_clock 的高精度版本

例子

#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
void func()
{
    // 获得当前时间,保存为system_start
    auto system_start = std::chrono::system_clock::now();
    std::this_thread::sleep_for(std::chrono::seconds(3s));
    // 获得时间差
    auto diff = std::chrono::system_clock::now() - system_start;
    // 强制转换为秒
    auto sec = std::chrono::duration_cast<std::chrono::seconds>(diff);
    // 打印
    std::cout << "this program runs:" << sec.count() << " seconds" << std::endl;
}
void func2()
{
    // 获得当前时间,保存为system_start
    auto steady_start = std::chrono::steady_clock::now();
    std::this_thread::sleep_for(std::chrono::seconds(3s));
    // 获得时间差
    auto diff = std::chrono::steady_clock::now() - steady_start;
    // 强制转换为秒
    auto sec = std::chrono::duration_cast<std::chrono::seconds>(diff);
    // 打印
    std::cout << "this program runs:" << sec.count() << " seconds" << std::endl;
}
int main()
{
    func();        
    func2();   // 虽然打印出来的值是一样的但 ,如果中途修改了系统时间,也不影响now()的结果)
}
// steady_clock example
#include <iostream>
#include <ctime>
#include <ratio>
#include <chrono>

int main ()
{
  using namespace std::chrono;

  steady_clock::time_point t1 = steady_clock::now();

  std::cout << "printing out 1000 stars...\n";
  for (int i=0; i<1000; ++i) std::cout << "*";
  std::cout << std::endl;

  steady_clock::time_point t2 = steady_clock::now();

  duration<double> time_span = duration_cast<duration<double>>(t2 - t1);

  std::cout << "It took me " << time_span.count() << " seconds.";
  std::cout << std::endl;

  return 0;
}

三个clock的精度问题

方式一

  • 标准库并不强制规定上述clock的精准度、epoch,“最小和最大timepoint的范围”。举个例子,你的system clock也许提供的是UNIX epoch(1970年1月1日),如果你还需要一个特定的epoch,或你关注的timepoint并非被你的clock涵盖,你就必须使用各种便捷函数查清楚
  • 例如,下面的函数打印某个clock的各种属性:

template<typename C>
void printClockData()
{
    std::cout << "- precision: ";
    typedef typename C::period P;
    if (std::ratio_less_equal<P, milli>::value){
        typedef typename std::ratio_multiply<P, kilo>::type TT;
        std::cout << fixed << double(TT::num) / TT::den << " milliseconds" << std::endl;
    }
    else {
        std::cout << fixed << double(P::num) / P::den << " seconds" << std::endl;
    }
    std::cout << "- si_steady: " << boolalpha << C::is_steady << std::endl;
}

  • 我们可以针对各种clock调用这个函数,例如:

int main()
{
    std::cout << "system_clock: " << std::endl;
    printClockData<std::chrono::system_clock>();
 
    std::cout << "\nhigh_resolution_clock: " << std::endl;
    printClockData<std::chrono::high_resolution_clock>();
 
    std::cout << "\nsteady_clock: " << std::endl;
    printClockData<std::chrono::steady_clock>();
}

  • 结果如下图所示:
    • 可以看到,system_clock和high_resolution_clock有着相同精度,100纳秒,而steady_clock的精度则是毫秒
    • 还可以看到,steady_clock和high_resolution_clock不能被调整
    • 还需要注意,在其他系统中情况也许完全不同,例如high_resolution_clock有可能和system_clock相同

img

方式二

#include <iostream>
#include <chrono>
using namespace std;
int main()
{
	cout << "system clock          : ";
	cout << chrono::system_clock::period::num << "/" << chrono::system_clock::period::den << "s" << endl;
	cout << "steady clock          : ";
	cout << chrono::steady_clock::period::num << "/" << chrono::steady_clock::period::den << "s" << endl;
	cout << "high resolution clock : ";
	cout << chrono::high_resolution_clock::period::num << "/" << chrono::high_resolution_clock::period::den << "s" << endl;
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库,计算机网络、操作系统刷题笔记33

数据库&#xff0c;计算机网络、操作系统刷题笔记33 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

自定义View的学习笔记1-1

这一系列主要是跟随扔物线的学习笔记。 自定义View主要是三个部分&#xff0c;绘制&#xff0c;布局&#xff0c;触摸反馈。 绘制是这三个部分中&#xff0c;最重要的一个。 先说绘制&#xff0c;所谓绘制&#xff0c;指的就是控件内容的显示。啥意思&#xff0c;比如我们作…

02 技术太卷我学Apex-级联值列表

02 技术太卷我学Apex-级联值列表 0 值列表概念 就是页面输入时从下拉列表中选择固定值。 值列表可以在APEX中【共享组件】-【其它组件】-【值列表】创建&#xff0c;也可以也页面上自己用sql语句&#xff08;一般需要级联值列表最好在页面上创建&#xff09;创建。 1 创建一…

Node版本锁定

Node版本锁定问题方案一、锁定Node版本二、自动切换Node版本问题 接手项目时&#xff0c;不知道项目所用的Node版本同一个项目&#xff0c;不同人用不同的Node版本&#xff0c;引起编译后的未知问题 方案 一、锁定Node版本 在package.json中配置 engines&#xff0c;限定项目…

【微电网】基于改进粒子群算法的微电网优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

云原生周刊 | 使用 ChatGPT 协助解决 Prometheus 告警

开源项目推荐 kubernetes-chatgpt-bot 这是一个适用于 Slack 的 ChatGPT 机器人&#xff0c;只要有监控告警发送到 Slack 频道中&#xff0c;你就可以通过机器人向 ChatGPT 咨询如何解决这个告警&#xff0c;ChatGPT 将会给出一个较为详细的解决方案。 Copacetic Copacetic …

WEB文件管理器和上传器:GleamTech FileUltimate 8.5.1.0

GleamTech FileUltimate适用于 ASP.NET Core、MVC 和 WebForms 的FileUltimate文件管理器和上传器 将文件管理器快速集成到您的 ASP.NET 应用程序或站点中。 使用访问控制浏览和管理文件。 接受具有高级上传功能的文件&#xff08;上传器也可作为独立组件使用&#xff09;。 提…

应用程序进程启动过程

1 应用程序进程简介 想要启动一个应用程序&#xff0c;首先要保证这个应用程序所需要的应用程序进程已经启动。 AMS 在启动应用程序时会检查这个应用程序所需要的应用程序进程是否已经存在&#xff0c;如果不存在就会请求 Zygote 进程启动需要的应用程序进程。 在 Zygote进程启…

2023牛客寒假算法基础集训营1--鸡玩炸蛋人(带权并查集) 诈骗题?

题目如下&#xff1a; 示例1 输入 6 4 1 2 2 3 1 3 4 6 0 0 0 0 0 0输出 14示例2 输入 6 4 1 2 2 3 1 3 4 6 0 0 0 0 2 0输出 1题目链接 题解 or 思路&#xff1a; 首先如果我们理解题意了&#xff0c;这个题是顶级诈骗。 因为是无向图&#xff0c;我们需要记录图中 环…

算法第十三期——BFS-双向广搜

双向广搜 应用场景&#xff1a;有确定的起点s和终点t&#xff1b;把从起点到终点的单向搜索&#xff0c;变换为分别从起点出发和从终点出发的“相遇”问题。操作&#xff1a;从起点s(正向搜索&#xff09;和终点t(逆向搜索&#xff09;同时开始搜索&#xff0c;当两个搜索产生…

编程太难不适合女生学?来看 N 多小姐姐的回应!

某女程序员&#xff1a;我要去互联网公司做程序员&#xff1f;网友&#xff1a;你疯了&#xff1f;程序员很累的... 女生不适合做程序员&#xff0c;还是去做产品经理吧。画外音&#xff1a;我去&#xff0c;产品经理不累吗&#xff1f;并不是女生不适合写代码&#xff0c;也不…

python cairosvg 库专题博客,10分钟掌握 cairosvg

cairosvg 库用于将 SVG 图像转换为其他图片格式。它使用 Cairo 库来绘制 SVG 图像&#xff0c;并支持将 SVG 图像转换为 PNG、PDF、PS、SVG 和 GIF 格式。 python cairosvgPython cairosvg 上手案例cairosvg 直接将 svg 图像转换为二进制数据cairosvg 库函数清单总结Python cai…

趣味三角——第1章——角

平面角是平面内相交但不在一条直线上的两条直线之间的倾角(A plane angle is the inclination to one another of two lines in a plane which meet one another and do not lie in a straight line.)。 ——Euclid(欧几里得), 元素(The Elements)&#xff0c;定义8。 几何实体…

【C++】Hash开散列,unordered_set(map) 的封装以及迭代器的实现

上一篇博客我们使用闭散列的方式实现了 Hash&#xff0c;其实在STL库unordered_set、unordered_map中底层是开散列的方式实现的Hash&#xff0c;所以&#xff0c;本篇博客就再使用开散列的方式实现Hash&#xff0c;并将unordered_set、unordered_map进行封装。 目录 一、开散…

C 数据结构1 —— 线性表-顺序表\单链表\双链表

文章目录1. 线性表1.1 定义1.2 特点2. 顺序表(顺序存储结构)2.1 定义(存储结构代码描述)2.2 插入元素2.2.1 图形演示2.2.2 代码表示2.3 删除元素2.3.1 图形演示2.3.2 代码表示2.4 完整代码2.5 动态分配数组3. 单链表(链式存储结构)3.1 定义(存储结构代码描述)3.2 单链表的读取3…

COCO_04 展示COCO格式数据集 目标框与分割mask

文章目录1 前言2 绘制GT2.1 绘制目标框与类别2.2 绘制分割mask3 AppendixA. mask polygon格式转化为图片格式参考1 前言 上篇文章介绍了如何制作COCO个数数据集的Dataset与Dataloader&#xff0c;并绘制了dataloader->batch的返回的信息&#xff0c;https://blog.csdn.net/…

【打卡】医学搜索Query相关性判断学习赛

入坑传送门 赛事介绍 文本匹配拥有广泛的应用场景&#xff0c;可以用于去除重复问题和文本相似度中。在本次学习中我们将学习&#xff1a; 如何计算文本之间的统计距离如何训练词向量 & 无监督句子编码BERT模型搭建和训练 上述步骤都是一个NLP算法工程师必备的基础&…

【GD32F427开发板试用】02-ADC规则组连续采样

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;Stark_GS ADC 简介及特点 器件中集成了一个 12 位 2.6 MSPS 多通道 ADC。 一共有19个多路复用通道&#xff1a;16个外部通道&#xff0c;1个…

office365删除错误发送的邮件

微软喜欢变&#xff0c;office365删个邮件真是不容易。 --管理员登录 Connect-IPPSSession -UserPrincipalName adminmydomain.onmicrosoft.com --创建一个 "deleteemail"的搜索项目&#xff0c;项目名可以任意起&#xff0c;这个名称后面在office365安全合规门户里…

libcurl简介及其编程应用

本文为学习笔记&#xff0c;整合课程内容以及下列文章&#xff1a; 其中&#xff0c;libcurl函数库常用字段解读部分&#xff1a; 参考博文&#xff1a;原文地址 作者&#xff1a;冬冬他哥哥 目录 libcurl简介 libcurl的使用 学会开源包使用的一般步骤 包的解读 重点是看…