Environment.TickCount 与 DateTime.Now
题
可以使用吗 Environment.TickCount
计算时间跨度?
int start = Environment.TickCount;
// Do stuff
int duration = Environment.TickCount - start;
Console.WriteLine("That took " + duration " ms");
因为 TickCount
已签名,并将在 25 天后滚动(需要 50 天才能达到所有 32 位,但如果您想了解数学意义,则必须废弃已签名的位),似乎风险太大而无用。
我在用着 DateTime.Now
反而。这是最好的方法吗?
DateTime start = DateTime.Now;
// Do stuff
TimeSpan duration = DateTime.Now - start;
Console.WriteLine("That took " + duration.TotalMilliseconds + " ms");
解决方案
使用秒表课程。在msdn上有一个不错的例子: http://msdn.microsoft的.com / EN-US /库/ system.diagnostics.stopwatch.aspx
Stopwatch stopWatch = Stopwatch.StartNew();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
其他提示
环境.TickCount 是基于 获取TickCount() WinAPI函数。它以毫秒为单位,但实际的精度约为15.6毫秒。所以你不能测量更短的时间间隔(否则你会得到0)
笔记: 返回的值为 Int32,因此该计数器每约 49.7 天滚动一次。您不应该用它来测量这么长的间隔。
日期时间.Ticks 是基于 获取系统时间作为文件时间()WinAPI 函数。它以 100 纳秒(十分之一微秒)为单位。DateTime.Ticks 的实际精度取决于系统。在XP上,系统时钟的增量约为15.6 ms,与Environment.TickCount中相同。在 Windows 7 上,其精度为 1 毫秒(而 Environemnt.TickCount 的精度仍为 15.6 毫秒),但是如果使用节能方案(通常在笔记本电脑上),它也可以降至 15.6 毫秒。
跑表 是基于 查询性能计数器() WinAPI函数(但如果您的系统不支持高分辨率性能计数器,则使用DateTime.Ticks)
使用秒表之前注意两个问题:
您可以通过简单的测试来评估系统的精度:
static void Main(string[] args)
{
int xcnt = 0;
long xdelta, xstart;
xstart = DateTime.UtcNow.Ticks;
do {
xdelta = DateTime.UtcNow.Ticks - xstart;
xcnt++;
} while (xdelta == 0);
Console.WriteLine("DateTime:\t{0} ms, in {1} cycles", xdelta / (10000.0), xcnt);
int ycnt = 0, ystart;
long ydelta;
ystart = Environment.TickCount;
do {
ydelta = Environment.TickCount - ystart;
ycnt++;
} while (ydelta == 0);
Console.WriteLine("Environment:\t{0} ms, in {1} cycles ", ydelta, ycnt);
Stopwatch sw = new Stopwatch();
int zcnt = 0;
long zstart, zdelta;
sw.Start();
zstart = sw.ElapsedTicks; // This minimizes the difference (opposed to just using 0)
do {
zdelta = sw.ElapsedTicks - zstart;
zcnt++;
} while (zdelta == 0);
sw.Stop();
Console.WriteLine("StopWatch:\t{0} ms, in {1} cycles", (zdelta * 1000.0) / Stopwatch.Frequency, zcnt);
Console.ReadKey();
}
你为什么担心翻车?只要您测量的持续时间低于24.9天并计算相对持续时间,您就可以了。系统运行的时间并不重要,只要您只关心自己运行时间的一部分(而不是直接执行小于或大于开始和结束点的比较)。即这样:
int before_rollover = Int32.MaxValue - 5;
int after_rollover = Int32.MinValue + 7;
int duration = after_rollover - before_rollover;
Console.WriteLine("before_rollover: " + before_rollover.ToString());
Console.WriteLine("after_rollover: " + after_rollover.ToString());
Console.WriteLine("duration: " + duration.ToString());
正确打印:
before_rollover: 2147483642
after_rollover: -2147483641
duration: 13
您不必担心标志位。 C#和C一样,让CPU处理这个。
这是我在嵌入式系统中计算时间之前遇到的常见情况。我永远不会比较之前<!> lt;例如,直接后滚动。我总是会执行减法来找到考虑翻转的持续时间,然后根据持续时间进行任何其他计算。
您可能需要 System.Diagnostics.StopWatch
。
如果您正在寻找Environment.TickCount
的功能但没有创建新Stopwatch
对象的开销,则可以使用静态Stopwatch.GetTimestamp()
方法(以及Stopwatch.Frequency
)来计算长时间跨度。因为GetTimestamp()
返回long
,它不会在很长一段时间内溢出(超过10万年,在我用来编写它的机器上)。它也比<=>准确得多,其最大分辨率为10到16毫秒。
使用
System.Diagnostics.Stopwatch
它有一个名为
的属性EllapsedMilliseconds
Environment.TickCount似乎比其他解决方案快得多:
Environment.TickCount 71
DateTime.UtcNow.Ticks 213
sw.ElapsedMilliseconds 1273
测量结果由以下代码生成:
static void Main( string[] args ) {
const int max = 10000000;
//
//
for ( int j = 0; j < 3; j++ ) {
var sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = Environment.TickCount;
}
sw.Stop();
Console.WriteLine( $"Environment.TickCount {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine( $"DateTime.UtcNow.Ticks {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine( $"sw.ElapsedMilliseconds {sw.ElapsedMilliseconds}" );
}
Console.WriteLine( "Done" );
Console.ReadKey();
}
这是一种更新的<!>放大器;更新了可能是最有用的答案的摘要<!> amp;此主题中的评论+额外的基准和变体:
首先要做的事情:正如其他人在评论中指出的那样,事情已经改变了过去的几年,并且用<!> quot; modern <!> Windows(Win XP ++)和.NET以及现代硬件没有或几乎没有理由不使用Stopwatch()。
请参阅
您应该使用秒表而不是。
我使用Environment.TickCount,因为:
- Stopwatch类不在Compact Framework中。
- 秒表使用与TickCount相同的基础计时机制,因此结果不会更准确或更准确。
- TickCount的环绕问题在很大程度上不太可能被击中(您必须让计算机运行27天,然后尝试测量恰好跨越换行的时间(即时)),即使你确实击中了它,结果也会是一个巨大的负时间跨度(所以它会很突出)。 醇>
话虽如此,我还建议使用秒表,如果你可以使用的话。或者你可以花大约1分钟写一个类似秒表的类来包装Environment.TickCount。
顺便说一句,我在秒表文档中没有看到提及底层计时器机制的环绕问题,所以我不会惊讶地发现秒表遇到了同样的问题。但同样,我也不会花时间担心它。我打算把它包装成一个秒表课,但Grzenio已经说了正确的话,所以我会给他一个提升。这种封装因素决定了哪种方式更好,这可以及时改变。我记得对于在一些系统上花费多少时间感到震惊,因此拥有一个可以实现最佳技术的地方非常重要。
对于一次性定时,写入
更简单Stopwatch stopWatch = Stopwatch.StartNew();
...dostuff...
Debug.WriteLine(String.Format("It took {0} milliseconds",
stopWatch.EllapsedMilliseconds)));
考虑到ElapsedTicks字段很长,我猜想TickCount中的宇宙不太可能的回绕甚至不太关注StopWatch。在我的机器上,StopWatch是高分辨率,每秒2.4e9滴答。即使按照这个速度,也需要超过121年的时间才能超过蜱虫领域。当然,我不知道封面下发生了什么,所以拿出一粒盐。但是,我注意到StopWatch的文档甚至没有提到回绕问题,而TickCount的文档也没有。