C#高精度计时的几种方法

    技术2025-01-22  11

    今天突然看到些文章关于高精度计时的一些方法,记得以前也在哪里看过有具体阐述过各种计时的精度误差范围,可能是网上文章,可能是书上,待以后想到再补上其他的,今天下总结下如下。

    我的CPU是双核E7500,2.93GHz。

     

    测试代码:

    void TestForVaryTime() { MTimer t = new MTimer(); //Console.WriteLine( t.GetAbsoluteTime()); //Console.WriteLine(t.GetElapsedTime()); t.Reset(); System.Threading.Thread.Sleep(897); Console.WriteLine("MTimer's 897ms is/r/n {0} s", t.GetTime()); /// DateTime.Now.Ticks long a = DateTime.Now.Ticks; System.Threading.Thread.Sleep(897); double c = DateTime.Now.Ticks - a; Console.WriteLine("/tDateTime.Now.Ticks's 897ms is/r/n/t {0} s", c / 10000000); ///Environment.TickCount int d1 = Environment.TickCount; System.Threading.Thread.Sleep(897); int d2 = Environment.TickCount - d1; Console.WriteLine("/t/tEnvironment.TickCount's 897ms is/r/n/t/t {0} ms", d2); }

    测试10次的输出:MTimer's 897ms is 0.897621838121961 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 891 ms MTimer's 897ms is 0.897406885438632 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 907 ms MTimer's 897ms is 0.897402539618527 s DateTime.Now.Ticks's 897ms is 0.90625 s The thread '<No Name>' (0x6c4) has exited with code 0 (0x0). Environment.TickCount's 897ms is 890 ms MTimer's 897ms is 0.897381569908716 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 891 ms MTimer's 897ms is 0.897400723847671 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 906 ms MTimer's 897ms is 0.897418077053209 s DateTime.Now.Ticks's 897ms is 0.90625 s Environment.TickCount's 897ms is 890 ms MTimer's 897ms is 0.897421558220524 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 891 ms MTimer's 897ms is 0.897402844126684 s DateTime.Now.Ticks's 897ms is 0.890625 s Environment.TickCount's 897ms is 906 ms MTimer's 897ms is 0.896567051944102 s DateTime.Now.Ticks's 897ms is 0.90625 s Environment.TickCount's 897ms is 890 ms MTimer's 897ms is 0.897400554676473 s DateTime.Now.Ticks's 897ms is 0.90625 s Environment.TickCount's 897ms is 891 ms

     

    MTimer类代码,在Jon.Hong的“提供一个获取高精度时间类”文章的基础上,针对多核CPU进行了少许修改,修改是否正确有待验证:

    using System.Runtime.InteropServices; using System.Security; /// <summary> /// 对于高精度测试我们应当使用QueryPerformanceFrequency函数和QueryPerformanceCounter函数。 /// 通过它们可以获得比Environment.TickCount更高的精确度。 /// 实际上Environment.TickCount就是在调用QueryPerformanceFrequency函数和QueryPerformanceCounter函数。 /// </summary> /// <example> /// MTimer t = new MTimer(); /// t.GetAbsoluteTime(); /// t.GetElapsedTime(); /// t.Reset(); /// t.GetTime(); /// </example> public class MTimer { #region private members private long ticksPerSecond = 0; private long elapsedTime = 0; private long baseTime = 0; #endregion #region windows API /// <summary> /// 获取时间的精度 /// </summary> /// <param name="PerformanceFrequency"></param> /// <returns></returns> [SuppressUnmanagedCodeSecurity] [DllImport("kernel32")] static private extern bool QueryPerformanceFrequency(ref long PerformanceFrequency); /// <summary> /// 获取时间计数 /// </summary> /// <param name="PerformanceCount"></param> /// <returns></returns> [SuppressUnmanagedCodeSecurity] [DllImport("kernel32")] static private extern bool QueryPerformanceCounter(ref long PerformanceCount); [DllImport("kernel32")] static extern IntPtr GetCurrentThread(); [DllImport("kernel32")] static extern IntPtr SetThreadAffinityMask(IntPtr hThread, IntPtr dwThreadAffinityMask); #endregion #region constructors /// <summary> /// new /// </summary> public MTimer() { // Use QueryPerformanceFrequency to get frequency of the timer if (!QueryPerformanceFrequency(ref ticksPerSecond)) throw new ApplicationException("Timer: Performance Frequency Unavailable"); Reset(); } #endregion #region public methods /// <summary> /// 重置时间相关计数器 /// </summary> public void Reset() { long time = 0; IntPtr threadId = GetCurrentThread(); IntPtr previous = SetThreadAffinityMask(threadId, new IntPtr(1)); QueryPerformanceCounter(ref time); SetThreadAffinityMask(threadId, previous); baseTime = time; elapsedTime = 0; } /// <summary> /// 获取当前与最近一次 reset 时间差,单位:秒 /// </summary> /// <returns>The time since last reset.</returns> public double GetTime() { long time = 0; IntPtr threadId = GetCurrentThread(); IntPtr previous = SetThreadAffinityMask(threadId, new IntPtr(1)); QueryPerformanceCounter(ref time); SetThreadAffinityMask(threadId, previous); return (double) (time - baseTime) / (double) ticksPerSecond; } /// <summary> /// 获取当前系统的时间 ticks 数 /// </summary> /// <returns>The current time in seconds.</returns> public double GetAbsoluteTime() { long time = 0; IntPtr threadId = GetCurrentThread(); IntPtr previous = SetThreadAffinityMask(threadId, new IntPtr(1)); QueryPerformanceCounter(ref time); SetThreadAffinityMask(threadId, previous); return (double) time / (double) ticksPerSecond; } /// <summary> /// 获取此次与上次调用此方法的两次时间差 /// </summary> /// <returns>The number of seconds since last call of this function.</returns> public double GetElapsedTime() { long time = 0; IntPtr threadId = GetCurrentThread(); IntPtr previous = SetThreadAffinityMask(threadId, new IntPtr(1)); QueryPerformanceCounter(ref time); SetThreadAffinityMask(threadId, previous); double absoluteTime = (double) (time - elapsedTime) / (double) ticksPerSecond; elapsedTime = time; return absoluteTime; } #endregion }

    最新回复(0)