「翻译」C# 中的高性能计时器(Daniel Strigl著,野比译)

Conmajia 2012-05-14 04:54:56
加精
嗯,这篇是存档,避免被时间冲走。

嗯,万恶的我又来刷版了。

--------------

这是2008年翻译的奥地利人Daniel Strigl的Hi-performance Timer in C#一文。

还是那句话,请尽量保留版权,这些老外的文章可以随便用,但都是有条件的,参见CPOL


先上源码


点我下载源码

p.s. 怪事:我发的资源都一分没收,为啥我的下载分会有500多分呢?

---------------------下面是正文了--------------------

[奥地利]Daniel Strigl 著 野比 译

来源:http://www.codeproject.com





简介

精确的时间计量方法在某些应用程序中是非常重要的。常用的 Windows API 方法 GetTickCount() 返回系统启动后经过的毫秒数。另一方面,GetTickCount() 函数仅有 1ms 的分辨精度,很不精确。

故而,我们要另外寻找一种方法来精确测量时间。

Win32 API 使用 QueryPerformanceCounter() 和 QueryPerformanceFrequency() 方法支持高精度计时。这些方法,比“标准的”毫秒精度的计时方法如 GetTickCount() 之类有高得多的精度。另一方面来说,在 C# 中使用“非托管”的 API 函数会有一定的开销,但比起使用一点都不精确的 GetTickCount() API 函数来说要好得多了。

第一个函数 QueryPerformanceCounter() 查询任意时刻高精度计数器的实际值。第二个函数 QueryPerformanceFrequency() 返回高精度计数器每秒的计数值。为了获得某一代码段经历的时间,你需要获得代码段开始前和结束后这两个计时时刻的高精度计数器实际值。这两个值的差指出了代码段执行所经历的时间。

然后通过将差除以每秒计数值(高精度计时器频率),就可以计算经过的时间了。

duration = (stop - start) / frequency
经过时间 = (停止时间 - 开始时间) / 频率

需要关于 QueryPerformanceCounter 和 QueryPerformanceFrequency 的更多信息,请参阅 MSDN 文档。

代码

下面的类实现了 QueryPerformanceCounter() 和 QueryPerformanceFrequency() API 函数的功能。


using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace Win32
{
internal class HiPerfTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(
out long lpFrequency);

private long startTime, stopTime;
private long freq;

// 构造函数
public HiPerfTimer()
{
startTime = 0;
stopTime = 0;

if (QueryPerformanceFrequency(out freq) == false)
{
// 不支持高性能计数器
throw new Win32Exception();
}
}

// 开始计时器
public void Start()
{
// 来让等待线程工作
Thread.Sleep(0);

QueryPerformanceCounter(out startTime);
}

// 停止计时器
public void Stop()
{
QueryPerformanceCounter(out stopTime);
}

// 返回计时器经过时间(单位:秒)
public double Duration
{
get
{
return (double)(stopTime - startTime) / (double) freq;
}
}
}
}


使用这个类很简单。只需要创建一个 HiPerfTimer 的实例,然后调用 Start() 开始计时,Stop() 停止计时。要获得经过的时间,调用 Duration() 函数即可。

参考下面的例子。


HiPerfTimer pt = new HiPerfTimer();     // 创建新的 HiPerfTimer 对象
pt.Start(); // 启动计时器
Console.WriteLine("Test\n"); // 需要计时的代码
pt.Stop(); // 停止计时器
Console.WriteLine("Duration: {0} sec\n",
pt.Duration); // 打印需要计时部分代码的用时


下面的图片是该例子在我系统上的输出。





--------野比见解--------

由于这个计时器精度太高,我想除了工控或采集等项目,其他地方应该是用不到的吧?
...全文
4640 101 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
101 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2012-06-20
  • 打赏
  • 举报
回复
精度太高了
Conmajia 2012-05-28
  • 打赏
  • 举报
回复
[Quote=引用 137 楼 的回复:]

野比,知道藤子不二雄是谁吗
[/Quote]

人才一个,可惜挂了
mimacuowuma 2012-05-22
  • 打赏
  • 举报
回复
谢谢分享
chenzhou896611 2012-05-22
  • 打赏
  • 举报
回复
感谢分享,那分走人。
xczhao777 2012-05-22
  • 打赏
  • 举报
回复
都是高手呀!
绿领巾童鞋 2012-05-22
  • 打赏
  • 举报
回复
野比,知道藤子不二雄是谁吗
Conmajia 2012-05-21
  • 打赏
  • 举报
回复
[Quote=引用 133 楼 的回复:]

顶一个啊!
[/Quote]

哦哦,你的头像很yd啊
wutian333 2012-05-21
  • 打赏
  • 举报
回复
好东西,不错不错
Anew_G 2012-05-21
  • 打赏
  • 举报
回复
感谢 自己只用过DataTime
beyond_winner 2012-05-20
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]
引用 17 楼 的回复:
像我都直接用DataTime的。哈哈哈
[/Quote]
lq834869349lq 2012-05-20
  • 打赏
  • 举报
回复
赞一个嘛
Conmajia 2012-05-19
  • 打赏
  • 举报
回复
[Quote=引用 118 楼 的回复:]

引用 117 楼 的回复:
引用 115 楼 的回复:

引用 113 楼 的回复:
曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。

单任务系统下是可以,这是汇编最常用的延时手段。
winNT下就算了吧


其实我觉的我们被电脑骗了,我们得到的并不是很精确到cc,就算单指令周期的cpu也没办法用一条指令完成读取,写reg,再加上各种ret。。不知道用watchdo……
[/Quote]

没那么低,us还是能够保证的
xky96 2012-05-19
  • 打赏
  • 举报
回复
[Quote=引用 117 楼 的回复:]
引用 115 楼 的回复:

引用 113 楼 的回复:
曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。

单任务系统下是可以,这是汇编最常用的延时手段。
winNT下就算了吧


其实我觉的我们被电脑骗了,我们得到的并不是很精确到cc,就算单指令周期的cpu也没办法用一条指令完成读取,写reg,再加上各种ret。。不知道用watchdog行不行,wd一般都分频了。。
[/Quote]
嗯,其实做成所谓的库,反而是不精确的,当然也可以将函数入出口的指令也计算在内,还得关闭优化。
wd精度要求不高,ms级够了吧
Conmajia 2012-05-19
  • 打赏
  • 举报
回复
[Quote=引用 115 楼 的回复:]

引用 113 楼 的回复:
曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。

单任务系统下是可以,这是汇编最常用的延时手段。
winNT下就算了吧
[/Quote]

其实我觉的我们被电脑骗了,我们得到的并不是很精确到cc,就算单指令周期的cpu也没办法用一条指令完成读取,写reg,再加上各种ret。。不知道用watchdog行不行,wd一般都分频了。。
wywnet 2012-05-19
  • 打赏
  • 举报
回复
不同多线程呢?
glongsoft 2012-05-19
  • 打赏
  • 举报
回复
在能用C#的场合还是用C#,不建议用C++!
Conmajia 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用 113 楼 的回复:]

曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。
[/Quote]

莫非是rdtsc。。
xky96 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用 113 楼 的回复:]
曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。
[/Quote]
单任务系统下是可以,这是汇编最常用的延时手段。
winNT下就算了吧
bigbaldy 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用 111 楼 的回复:]

引用 108 楼 的回复:

根本不需要调用API,stopwatch已经包含QueryPerformanceCounter()和QueryPerformanceFrequency() 的功能了

Stopwatch sw = new Stopwatch();
sw.Start();
do something
sw.Stop();
long result= sw.Elapsed……
[/Quote]

恩,我刚开始也是用的你的那种方法,突然一天无意中发现Stopwatch中有一个Frequency,然后就试了一下,结果和这俩API的效果一样,.net库实在是太强大了,我刚开始很多东西都调API,后来发现,大部分功能库里已经有了
bluevalley2008 2012-05-18
  • 打赏
  • 举报
回复
曾经写过一个C的库,内联汇编到可以精确到时钟周期。。。
加载更多回复(81)

111,092

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧