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

.NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...

 

我们有很多种方法评估一个方法的执行耗时,比如使用性能分析工具,使用基准性能测试。不过传统的在代码中编写计时的方式依然有效,因为它可以生产环境或用户端得到真实环境下的执行耗时。

如果你希望在 .NET/C# 代码中编写计时,那么阅读本文可以获得一些建议。阅读本文也可以了解到 QueryPerformanceCounterGet­System­Time­As­File­Time 等方法的差异。


 

本文内容

      • 基本的计时
      • 结论:使用什么方法计时
      • 各种计时 API 及其比较
        • 基于系统性能计数器(QPC)的 API
        • 基于系统时间的 API
        • 基于 QPC 和系统时间的 API
        • 参考资料

 

基本的计时

计时一般采用下面这种方式,在方法执行之前获取一次时间,在方法结束之后再取得一次时间。

// 在方法开始之前。
Foo();
// 在方法执行之后。

这样,前后两次获取的时间差即为方法 Foo 的执行耗时。

这里我不会提到性能测试工具或者基准性能测试这些方法,因为这些测试代码不会运行于用户端。你可以阅读以下博客获得这两者的使用:

  • C# 标准性能测试 - 林德熙
  • C# 标准性能测试高级用法 - 林德熙
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法) - 吕毅

结论:使用什么方法计时

先说结论:System.Diagnostics 命名空间下有一个 Stopwatch 类。如果你要为你方法的执行时间进行统计,那么就使用这个类。

Stopwatch 类有一些静态属性、也有一些实例方法和实例属性。此类型的时间统计是按照高性能和高精度的要求来做的,于是你可以用它获得高精度的计时效果。不过,如果你对性能要求近乎苛刻,例如你的方法会被数百万次或更高频地执行,那么就需要开始斟酌如何调用里面的属性了。

简单的使用如下面这样:

var watch = Stopwatch.StartNew();
Foo();
watch.Stop();
var elapsed = watch.Elapsed;

当然,你也可以直接使用 Stopwatch 的构造函数,new 出来之后再 Start,不过 StartNew 静态方法可以将两句合并为一句。

各种计时 API 及其比较

计时还有很多的方法,你可以针对不同需求场景使用不同的方法。不过,如果你根本没有了解过其他方法的话,那么建议直接使用上面的 Stopwatch,不要想太多。

现在,我们看看 Windows 下的计时还有哪些 API:

  • 基于 QPC 的高精度 API
    • Query­Performance­Counter
    • Query­Performance­Frequency
  • 基于系统时间的非高精度 API
    • Get­Tick­Count, Get­Tick­Count64
    • Get­Message­Time
    • Get­System­Time, Get­Local­Time, Get­System­Time­As­File­Time
    • Query­Interrupt­Time, Query­Unbiased­Interrupt­Time
  • 基于 QPC 和系统时间的 API
    • Get­System­Time­Precise­As­File­Time
    • Query­Interrupt­Time­Precise, Query­Unbiased­Interrupt­Time­Precise

基于系统性能计数器(QPC)的 API

QueryPerformanceCounter,微软文档中把它称之为 QPC。

一般情况下使用的 QueryPerformanceCounter,内核驱动开发者使用的 KeQueryPerformanceCounter 和 .NET 开发者使用的 System.Diagnostics.Stopwatch 都是基于 QPC 的 API。

QPC 是通过计算机上独立运行的高精度硬件计时模块来获得时间戳的。这意味着,使用此 API 获得的时间戳是本机时间戳,不包含任何时区等信息。

由于 QPC 的高精度特性,所以非常适合在单个设备上测量一个小段时间的时间间隔。而这也符合我们本文一开始说到的方法执行耗时测量需求。

QueryPerformanceCounter 得到的值是 Ticks,单位是 100 ns。

1 tick  = 100 ns
1 us    = 1000 ns
1 ms    = 1000 us
1 s     = 1000 ms

基于系统时间的 API

如果你的需求不止是测量获取一个时间间隔,而是需要一个长期保存的时间,或者需要将时间与其他设备进行通信,那么基于单台设备的 QPC 就不符合要求了。

GetSystemTimeAsFileTime 可以用来获取系统时钟时间。这个时间就是基于系统时钟的,所以如果你的时间戳是用来通信的,那么就很有用。当然,如果要在设备之间进行与时间信息相关的同步,还可能需要使用 NTP(Network Time Protocol)先同步时间。

DateTime.Now 获取时间的方法就是这个:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern long GetSystemTimeAsFileTime();

这里有一些比较有趣的说法,基于系统时间的 API 也会说成是获取高精度时间,那么跟 QPC 有什么不同呢?

这里我只能拿英文来说话了。来自微软的 Raymond Chen 在它的 The Old New Thing 一书中说,基于系统时间的 API 获取的时间戳精度用的是 “所谓的 Precise”,但实际上应该称之为 “Accurate”,而 QPC 才能称之为实质上的 “Precise”。纠结起来就是 QPC 比基于系统时间的 API 得到的时间戳精度更高。

基于 QPC 和系统时间的 API

Get­System­Time­Precise­As­File­Time 这些 API 既可以获得 QPC 的高精度,又与系统时钟相关,于是你可以使用这些 API 同时获得以上测量的好处。当然,这以性能成本为代价的。


参考资料

  • Acquiring high-resolution time stamps - Microsoft Docs
  • How accurate are the various Windows time-querying functions? – The Old New Thing
  • windows平台时间函数性能比较QueryPerformanceCounter,GetTickCount,ftime,time,GetLocalTime,GetSystemTimeAsFileTime - 小 楼 一 夜 听 春 雨 - 博客园
  • c# - Is DateTime.Now the best way to measure a function’s performance? - Stack Overflow
  • c# - How do I measure how long a function is running? - Stack Overflow
  • c# - Calculate the execution time of a method - Stack Overflow
  • Stopwatch.IsHighResolution Field (System.Diagnostics) - Microsoft Docs
  • Stopwatch.cs
  • timespan.cs

转载于:https://www.cnblogs.com/walterlv/p/10236398.html

相关文章:

  • jmeter查看结果树中响应数据Unicode转换成中文
  • 牛客网——反序输出
  • python-24: re 模块 之三 re.compile
  • 常用安全测试用例(二)
  • 查看GPU占用率以及指定GPU加速程序
  • 基于JAVA的内存管理模拟
  • 线索二叉树
  • [源码和文档分享]基于rabbitMQ的微服务架构消息组件设计与实现
  • TYPORA的使用手册
  • python 断言 assert
  • 爬虫(二)之scrapy框架
  • three.js入门系列之视角和辅助线
  • elementui 走马灯图片自适应
  • CSS浮动(一)---Float
  • mode_w
  • 《Java编程思想》读书笔记-对象导论
  • 2017 年终总结 —— 在路上
  • Java 多线程编程之:notify 和 wait 用法
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • opencv python Meanshift 和 Camshift
  • Wamp集成环境 添加PHP的新版本
  • 算法---两个栈实现一个队列
  • 听说你叫Java(二)–Servlet请求
  • 微信开源mars源码分析1—上层samples分析
  • 我感觉这是史上最牛的防sql注入方法类
  • 限制Java线程池运行线程以及等待线程数量的策略
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (四)鸿鹄云架构一服务注册中心
  • (转)菜鸟学数据库(三)——存储过程
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .net项目IIS、VS 附加进程调试
  • /boot 内存空间不够
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @RequestMapping-占位符映射
  • [C++基础]-入门知识
  • [EULAR文摘] 利用蛋白组学技术开发一项蛋白评分用于预测TNFi疗效
  • [Google Guava] 1.1-使用和避免null
  • [nlp] tokenizer
  • [p4] Uncheckout other user‘s file?
  • [Qt]设置窗口图标和EXE应用程序图标