.NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
我们有很多种方法评估一个方法的执行耗时,比如使用性能分析工具,使用基准性能测试。不过传统的在代码中编写计时的方式依然有效,因为它可以生产环境或用户端得到真实环境下的执行耗时。
如果你希望在 .NET/C# 代码中编写计时,那么阅读本文可以获得一些建议。阅读本文也可以了解到 QueryPerformanceCounter
、GetSystemTimeAsFileTime
等方法的差异。
基本的计时
计时一般采用下面这种方式,在方法执行之前获取一次时间,在方法结束之后再取得一次时间。
// 在方法开始之前。
Foo();
// 在方法执行之后。
这样,前后两次获取的时间差即为方法 Foo
的执行耗时。
这里我不会提到性能测试工具或者基准性能测试这些方法,因为这些测试代码不会运行于用户端。你可以阅读以下博客获得这两者的使用:
结论:使用什么方法计时
先说结论: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
QueryPerformanceCounter
QueryPerformanceFrequency
- 基于系统时间的非高精度 API
GetTickCount
,GetTickCount64
GetMessageTime
GetSystemTime
,GetLocalTime
,GetSystemTimeAsFileTime
QueryInterruptTime
,QueryUnbiasedInterruptTime
- 基于 QPC 和系统时间的 API
GetSystemTimePreciseAsFileTime
QueryInterruptTimePrecise
,QueryUnbiasedInterruptTimePrecise
基于系统性能计数器(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
GetSystemTimePreciseAsFileTime
这些 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
.NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)的更多相关文章
- 代码中看见一共8个变量参数{SEO,0,0,0,0,0,0,0} 解读!{Top,0,0,0,0,0,0,Top}{Nav,0,0,0,0,0,0,Nav}
代码中看见{SEO,0,0,0,0,0,0,0}{Top,0,0,0,0,0,0,Top}{Nav,0,0,0,0,0,0,Nav}解读! 举个例子: {GetNew,977,0,23,500,0,0 ...
- Java基础学习总结(81)——如何尽可能的减少Java代码中bug
Java编程语言的人气自然无需质疑,从Web应用到Android应用,这款语言已经被广泛用于开发各类应用及代码中的复杂功能. 不过在编写代码时,bug永远是困扰每一位从业者的头号难题.在今天的文章中, ...
- java中异常抛出后代码还会继续执行吗
今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element){ i ...
- 代码在ie9中不能正确执行
<!DOCTYPE html> <html> <head lang="zh"> <meta charset="UTF-8&quo ...
- Java中普通代码块,构造代码块,静态代码块执行顺序
//执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 1 //普通代码块 ...
- SQL语句在查询分析器中可以执行,代码中不能执行
问题:SQL语句在查询分析器中可以执行,代码中不能执行 解答:sql中包含数据库的关键字,将关键字用[]括起来,可以解决. 后记:建数据库的时候尽量避免使用关键字. 例子: sql.Format(&q ...
- java中的代码块执行顺序
/* 代码块:在Java中,使用{}括起来的代码被称为代码块. 根据其位置和声明的不同,可以分为 局部代码块:局部位置,用于限定变量的生命周期. 构造代码块:在类中的成员位置,用{}括起来的代码.每次 ...
- 利用Roslyn把C#代码编译到内存中并进行执行
Tugberk Ugurlu在其博文<Compiling C# Code Into Memory and Executing It with Roslyn>中给大家介绍了一种使用.NET下 ...
- jsp页面中的代码执行加载顺序介绍
1. java是在服务器端运行的代码,jsp在服务器的servlet里运行,而javascript和html都是在浏览器端运行的代码.所以加载执行顺序是是java>jsp>js. 2. j ...
随机推荐
- postgresql主从复制
本文章以rpm包方式安装,版本为9.3.4 一.postgresql安装 postgresql93-9.3.4-1PGDG.rhel6.x86_64.rpm postgresql93-libs-9.3 ...
- HTML&CSS&Javascript脑图
今天看了极客学院的CSS3部分,加上前几天看过的HTML5部分,现在对HTML和CSS的基础有了系统的认识,正好发现这张图,简直Perfect! 感谢脑图的制作人,虽然不知道是谁,但能把HTML.CS ...
- 文件上传—SSH框架文件上传
1.准备上传的api组件 <dependency> <groupId>commons-io</groupId> <artifactId>commons- ...
- 1linux的基本命令
查看命令的帮助信息man 命令名 文件操作touch 建立文件 (对于已存在文件,更新时间)cat 查看文件 (-n 自动加上行号)rm 删除文件cp 拷贝文件mv 移动/重命名文件more 分页查看 ...
- Eclipse自动提示
在java的自动激活触发器里输入:abcdefghijklmnopqrstuvwxyz.
- Python面试题目之列表去重并维持原来顺序
题目: 列表去掉重复元素,并保持原来的排序 方法一: # 待处理的列表 L1 = [111,44,55,33,22,11] # 利用集合set的属性,去重 s1 = set(L1) # 把集合转化为列 ...
- bzoj1999 / P1099 树网的核
P1099 树网的核 (bzoj数据加强) 前置知识:树的直径 (并不想贴我的智障写法虽然快1倍但内存占用极大甚至在bzoj上MLE) 正常写法之一:用常规方法找到树的直径,在直径上用尺取法找一遍,再 ...
- 微信小程序:WXSS 样式
微信小程序:WXSS 样式 一.WXSS 样式 XSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改. 1,新增了尺寸单位: 在写 CSS 样式时,开发者需要考虑到手机设备的屏 ...
- 自动化运维工具SaltStack安装配置
SaltStack是一种全新的基础设置管理方式,部署轻松,在几分钟内可运作起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯.通过部署SaltStack环境,我们可以在成千上万台服务 ...
- linux内核分析第八周-理解进程调度时机跟踪分析进程调度与进程切换的过程
实验原理: 一.调度时机 不同类型的进程有不同的调度需求 第一种分类: I/O-bound 频繁的进行I/O 通常会花费很多时间等待I/O操 ...