C#中精确计时的一点收获
以下所有代码运行环境:Windows 2003, Intel(R) Core(TM) 2 Duo CPU E8400 @ 3.00GHz 2.99GHz,2.96GB内存
根据综合网上的一些文章,精确计时主要有以下几种方式
1 调用WIN API中的GetTickCount
[DllImport("kernel32")]
static extern uint GetTickCount();
从操作系统启动到现在所经过的毫秒数,精度为1毫秒,经简单测试发现其实误差在大约在15ms左右
缺点:返回值是uint,最大值是2的32次方,因此如果服务器连续开机大约49天以后,该方法取得的返回值会归零
用法:
uint s1 = GetTickCount();
Thread.Sleep();
Console.WriteLine(GetTickCount() - s1); //单位毫秒
2 调用WIN API中的timeGetTime 推荐
[DllImport("winmm")]
static extern uint timeGetTime();
常用于多媒体定时器中,与GetTickCount类似,也是返回操作系统启动到现在所经过的毫秒数,精度为1毫秒。
一般默认的精度不止1毫秒(不同操作系统有所不同),需要调用timeBeginPeriod与timeEndPeriod来设置精度
[DllImport("winmm")]
static extern void timeBeginPeriod(int t);
[DllImport("winmm")]
static extern void timeEndPeriod(int t);
缺点:与GetTickCount一样,受返回值的最大位数限制。
用法:
timeBeginPeriod();
uint start = timeGetTime();
Thread.Sleep();
Console.WriteLine(timeGetTime() - start); //单位毫秒
timeEndPeriod();
3 调用.net自带的方法System.Environment.TickCount
获取系统启动后经过的毫秒数。经反编译猜测它可能也是调用的GetTickCount,但是它的返回值是int,而GetTickCount与timeGetTime方法的原型中返回值是DWORD,对应C#中的uint,难道.NET对System.Environment.TickCount另外还做了什么处理么?
缺点:与GetTickCount一样,受返回值的最大位数限制。
用法:
int aa = System.Environment.TickCount;
Thread.Sleep();
Console.WriteLine(System.Environment.TickCount - aa); //单位毫秒
注:经过测试,发现GetTickCount、System.Environment.TickCount也可以用timeBeginPeriod与timeEndPeriod来设置精度,最高可将精度提高到1毫秒。不知是什么原因?
4 调用WIN API中的QueryPerformanceCounter
[DllImport("kernel32.dll ")]
static extern bool QueryPerformanceCounter(ref long lpPerformanceCount);
用于得到高精度计时器(如果存在这样的计时器)的值。微软对这个API解释就是每秒钟某个计数器增长的数值。
如果安装的硬件不支持高精度计时器,函数将返回false需要配合另一个API函数QueryPerformanceFrequency。
[DllImport("kernel32")]
static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);
QueryPerformanceFrequency返回硬件支持的高精度计数器的频率,如果安装的硬件不支持高精度计时器,函数将返回false。
用法:
long a = ;
QueryPerformanceFrequency(ref a);
long b = , c = ;
QueryPerformanceCounter(ref b);
Thread.Sleep();
QueryPerformanceCounter(ref c);
Console.WriteLine((c - b) / (decimal)a); //单位秒
精度为百万分之一秒。而且由于是long型,所以不存在上面几个API位数不够的问题。
缺点:在一篇文章看到,该API在节能模式的时候结果偏慢,超频模式的时候又偏快,而且用电池和接电源的时候效果还不一样(笔记本)
原文地址:http://delphi.xcjc.net/viewthread.php?tid=1570
未经过超频等测试,如果是真的,那该API出来的结果就可能不准。
5 使用.net的System.Diagnostics.Stopwatch类 推荐
Stopwatch 在基础计时器机制中对计时器的刻度进行计数,从而测量运行时间。如果安装的硬件和操作系统支持高分辨率性能的计数器,则 Stopwatch 类将使用该计数器来测量运行时间;否则,Stopwatch 类将使用系统计数器来测量运行时间。使用 Frequency 和 IsHighResolution 两个静态字段可以确定实现 Stopwatch 计时的精度和分辨率。
实际上它里面就是将QueryPerformanceCounter、QueryPerformanceFrequency两个WIN API封装了一下,如果硬件支持高精度,就调用QueryPerformanceCounter,如果不支持就用DateTime.Ticks来计算。
用法:
Stopwatch sw = new Stopwatch();
sw.Start();
Thread.Sleep();
sw.Stop();
Console.WriteLine(sw.ElapsedTicks / (decimal)Stopwatch.Frequency);
6 使用CPU时间戳进行更高精度计时
原文地址:http://www.chinaunix.net/jh/23/110190.html
该方法的原理我不是很明白,硬件知识太匮乏了。精度是ns
在C#中要用该方法必须先建立一个托管C++项目(因为要内嵌汇编),编译成DLL供c#调用,有点麻烦。
C++代码:
// MLTimerDot.h
#pragma once
using namespace System;
namespace MLTimerDot {
//得到计算机启动到现在的时钟周期
unsigned __int64 GetCycleCount(void)
{
_asm _emit 0x0F
_asm _emit 0x31
}
//声明 .NET 类
public __gc class MLTimer
{
public:
MLTimer(void)
{
}
//计算时钟周期
UInt64 GetCount(void)
{
return GetCycleCount();
}
};
}
C#调用:
long a = ;
QueryPerformanceFrequency(ref a); MLTimerDot.MLTimer timer = new MLTimerDot.MLTimer();
ulong ss= timer.GetCount();
Thread.Sleep();
Console.WriteLine((timer.GetCount() - ss) / (decimal)a);
缺点:和QueryPerformanceCounter一样,结果不太稳定。
我的结论:常规应用下timeGetTime完全够用了,将精度调到1毫秒,大部分境况都够用。System.Diagnostics.Stopwatch由于调用方便,也推荐使用
C#中精确计时的一点收获的更多相关文章
- C#中精确计时的一点收获 【转】
C#中精确计时的一点收获 [转] 以下所有代码运行环境:Windows 2003, Intel(R) Core(TM) 2 Duo CPU E8400 @ 3.00GHz 2.99GHz,2.96G ...
- C#中精确计时的一点收获 Stopwatch
http://www.cnblogs.com/jintianhu/archive/2010/09/01/1815031.html 参考: https://www.cnblogs.com/kissdod ...
- c#多态之抽象类与接口的一点收获~~
多态之抽象类与接口的相似点及不同点,刚学习的一点收获,或许不是很完整,借鉴看视频及一些被人写的文章自己写的下的一些心得!以便之久复习使用! 一.抽象类 (1) 抽象方法只作声明,而不包含实现,可以看成 ...
- C语言中常用计时方法总结
转自:http://blog.csdn.net/fz_ywj/article/details/8109368 C语言中常用计时方法总结 1. time() 头文件:time.h 函数原型:time_t ...
- windows下的C/C++精确计时
由于我要测试线性筛法的速度,用上了C/C++精确计时.此时传统的clock()方法不够用了,我们需要另一种测量的办法,即CPUTicks/CPUFreq.如何实现呢? #include <win ...
- C# 广播TS流精确计时发送
广播传输相关的项目,需求是UDP发送TS到IP/ASI网关,网关经过ASI输出到激励器,再由激励器通过射频天线输出,接收端为终端机顶盒. 因为以前没有怎么接触过广播相关的东西,一开始认为用C#写个UD ...
- Golang中WaitGroup使用的一点坑
Golang中WaitGroup使用的一点坑 Golang 中的 WaitGroup 一直是同步 goroutine 的推荐实践.自己用了两年多也没遇到过什么问题.直到一天午睡后,同事扔过来一段奇怪的 ...
- [转载]对iOS开发中内存管理的一点总结与理解
对iOS开发中内存管理的一点总结与理解 做iOS开发也已经有两年的时间,觉得有必要沉下心去整理一些东西了,特别是一些基础的东西,虽然现在有ARC这种东西,但是我一直也没有去用过,个人觉得对内存操作 ...
- 【ABAP系列】SAP ABAP中关于commit的一点解释
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP中关于commi ...
随机推荐
- iOS archive(归档)的总结
http://www.cnblogs.com/ios8/p/ios-archive.html
- UIScrollView 代理方法
在使用UIScrollView和它的子类UITableView时,有时需要在不同操作状态下,做不同的响应. 如何截获这些状态,如正在滚动,滚动停止等,使用UIScrollViewDelegate_Pr ...
- Delphi 接口托管实现
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- C# 操作系统回收站
主要目的:对系统回收站的文件进行操作. 首先添加引用,引入shell32.dll. /// <summary> /// 对回收站的文件进行还原.删除.剪切等操作 /// </summ ...
- [Head First Python]4. summary
1- strip()方法可以从字符串去除不想要的空白符 (role, line_spoken) = each_line.split(":", 1) line_spoken = li ...
- 1008 Gnome Tetravex
练习使用DPS的题,不知道有无别的做法,思路不复杂.形式是统计并且进行数字配对. #include <stdio.h> ][],note[],ans[]; void ini(){ int ...
- ajax请求解析springmvc返回的json数据
需要使用的框架 spring3.0 jquery1.9.0(简化ajax开发的js库) Jackson(json处理器):jackson-core-asl-1.9.2.jar,jackson-mapp ...
- Effective Java设定游戏 - 就是爱Java
首先,我们先设定游戏,一个网页游戏的基本场景,主角拥有各种能力,但一开始数值都只有系统初始,随着故事的发展,会接触到各种不同的场景,获得提升角色的道具与装备,来参与更高难度的任务. 阅读全文>& ...
- 系统service
Context.TELEPHONY_SERVICE TelephonyManager tManager = (TelephonyManager)getSystemService(Context.TEL ...
- ant的入门 配置与安装
最近需要用ant来生成文件,java类.我才开始了解了这个工具.仔细看了一下,感觉这个小工具的强大功能. 博主也是初学者,在网上收集了资料,尝试了配置:感觉有些高手写得不错变引用之. 配置如下: 以上 ...