C# 的1ms延时函数

1 调用WIN API中的GetTickCount

[DllImport("kernel32")]
static extern uint GetTickCount();

从操作系统启动到现在所经过的毫秒数,精度为1毫秒,经简单测试发现其实误差在大约在15ms左右

缺点:返回值是uint,最大值是2的32次方,因此如果服务器连续开机大约49天以后,该方法取得的返回值会归零

用法:

1
2
3
uint  s1 = GetTickCount();
Thread.Sleep(2719);
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一样,受返回值的最大位数限制。

用法:

1
2
3
4
5
timeBeginPeriod(1);
uint  start = timeGetTime();
Thread.Sleep(2719);
Console.WriteLine(timeGetTime() - start);  //单位毫秒
timeEndPeriod(1);

 3 调用.net自带的方法System.Environment.TickCount

获取系统启动后经过的毫秒数。经反编译猜测它可能也是调用的GetTickCount,但是它的返回值是int,而GetTickCount与timeGetTime方法的原型中返回值是DWORD,对应C#中的uint,难道.NET对System.Environment.TickCount另外还做了什么处理么?
缺点:与GetTickCount一样,受返回值的最大位数限制。

用法:

1
2
3
int  aa = System.Environment.TickCount;
Thread.Sleep(2719);
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。

用法:

1
2
3
4
5
6
7
long  a = 0;
QueryPerformanceFrequency( ref  a);
long  b = 0, c = 0;
QueryPerformanceCounter( ref  b);
Thread.Sleep(2719);
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来计算。

用法:

1
2
3
4
5
Stopwatch sw = new  Stopwatch();
sw.Start();
Thread.Sleep(2719);
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++代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 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#调用:

1
2
3
4
5
6
7
long  a = 0;
QueryPerformanceFrequency(ref a);
 
MLTimerDot.MLTimer timer = new  MLTimerDot.MLTimer();
ulong ss= timer.GetCount();
Thread.Sleep(2719);
Console.WriteLine((timer.GetCount() - ss) / (decimal)a);

缺点:和QueryPerformanceCounter一样,结果不太稳定。

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页