Environment.TickCount与DateTime.Now


68

可以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");

13
除了无关紧要的是,如果您确实使用DateTime进行与日期相关的数学计算,请始终使用DateTime.UtcNow作为DateTime.Now容易受到夏令时的影响...您的计算可能会偏离一个小时,或更糟糕的是出现负数。
Scott Hanselman,2009年

5
@Scott:值得一提的是:即使使用UtcNow,也存在计划的NTP同步的问题:在这些更新之后(在我的PC上),系统时间被更改的时间大约为10秒。
Groo

数学实际上并没有那么复杂……int duration = unchecked((int)((uint)Environment.TickCount - (uint)start));无论翻转如何,都会给您正确的答案。(理想情况下,int除非绝对需要,否则您可以跳过演员表。)
AnorZaken 2015年

@AnorZaken:实际上,您不需要任何转换,如本页其他位置所述
格伦Slayden

@GlennSlayden您是正确的-我的uint强制转换毫无意义,而且由于我将其强制转换为int,所以无论如何都没有任何意义。接得好。(另外,在不受限制的上下文中强制转换为int也是我可疑的选择。)
AnorZaken

Answers:


72

使用秒表类。msdn上有一个不错的示例:http : //msdn.microsoft.com/zh-cn/library/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;

1
Stopwatch类仅在.NET Framework 2.0及更高版本中可用。在较旧的版本中,您将使用TickCount(可能与TimeSpan结合使用)来检查是否已超过25天边界。
符文格里姆斯塔德

在早期版本中,您将使用标记为safe和msdn.microsoft.com/en-us/library/ms901807.aspx的p / invoke调用,而不是TickCount。
亨里克

1
如果您的程序所运行的硬件缺少高分辨率计时器,则秒表与日期时间一样危险。请参阅connect.microsoft.com/VisualStudio/feedback/details/741848/…以及以下Joel的答案。
rkagerer 2013年

我找不到可移植类库的秒表,因此您必须使用一些解决方法。
Alexey Strakh 2013年

98

Environment.TickCount基于WinAPI函数GetTickCount()。单位为毫秒,但实际精度约为15.6毫秒。因此,您无法测量更短的时间间隔(否则您将获得0)

注意:返回值是Int32,因此此计数器每隔约49.7天滚动一次。您不应该使用它来测量如此长的间隔。

DateTime.Ticks基于WinAPI函数GetSystemTimeAsFileTime()。只需100纳秒(十分之一微秒)。DateTime.Ticks的实际精度取决于系统。在XP上,系统时钟的增量约为15.6 ms,与Environment.TickCount中的相同。在Windows 7上,其精度为1毫秒(而Environem.TickCount的精度仍为15.6毫秒),但是,如果使用了节能方案(通常在笔记本电脑上),则精度也可能下降到15.6毫秒。

秒表基于QueryPerformanceCounter() WinAPI函数(但是,如果系统不支持高分辨率性能计数器,则使用DateTime.Ticks)

在使用秒表之前,请注意两个问题:

  • 在多处理器系统上可能不可靠(请参阅MS kb895980kb896256
  • 它可以是不可靠的,如果CPU频率变化(读文章)

您可以通过简单的测试来评估系统的精度:

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();
}

只是对循环的注释-应该使用Thread.SpinWait,而不是for循环,这可以确保循环没有被优化(您指定“ waste”循环是您所需要的语义)。除此之外,它应该或多或少等于for周期。
a安2014年

@Luaan:谢谢,我更改了示例代码以显示精度。
mistika 2014年

1
非常详细的解释。在我的win10桌面上,结果类似于您的Win7报告。秒表看起来像高精度。DateTime:1,0278 ms,在21272周期内环境:16 ms,在4786363周期内秒表:0,00087671156014329 ms,在1个周期内
Patrick Stalph

3
QueryPerformanceCounter()如今很可靠:请参阅blogs.msdn.microsoft.com/oldnewthing/20140822-01/?p=163msdn.microsoft.com/en-us/library/windows/desktop/…“问:QPC是否在多处理器系统,多核系统以及具有超线程的系统上可靠地工作?A:是”,“ Q:QPC精度是否受电源管理或Turbo Boost技术引起的处理器频率变化的影响?A:否”
Lu55

4
如今,您提到的“问题”基本上是无关紧要的。它们适用于Windows 2000,Windows 2003和Windows XP。如果您正在运行这些系统,则问题将比计时器是否准确要大。
Mark

27

您为什么担心结余?只要您测量的持续时间在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处理。

在嵌入式系统中,我经常遇到这种情况。例如,我永远不会直接比较beforerollover <afterrollover。我将始终执行减法以找到考虑了过渡的持续时间,然后根据该持续时间进行任何其他计算。


3
最佳答案IMO。这也不会“在50天后爆炸”,除非您试图使用它来跟踪超过50天的时间,这似乎不太可能。+1包括以一种容易测试的方式对此工作的可靠证明。由于多核CPU的问题(目前几乎每台PC都存在这种问题),StopWatch是无用的一类。
eselk

1
注意:此示例仅在构建代码时不检查算术上溢/下溢(默认情况下为关闭)时才有效。如果将其打开(项目设置>生成>高级...>检查算术上溢/下溢),则代码将升高System.OverflowException : Arithmetic operation resulted in an overflow
Lu55

@eselk秒表可靠时下:看stackoverflow.com/questions/243351/...
Lu55


9

如果您正在寻找的功能Environment.TickCount但又没有创建新Stopwatch对象的开销,则可以使用staticStopwatch.GetTimestamp()方法(以及Stopwatch.Frequency)来计算较长的时间跨度。因为GetTimestamp()返回a long,所以它不会在非常非常长的时间内溢出(超过100,000年,在我用来编写此代码的机器上)。它也比Environment.TickCount最高分辨率10到16毫秒要精确得多。


不幸的Stopwatch.GetTimestamp()是,它并不方便,Environment.TickCount因为它返回一些抽象的滴答声,而不是普通的时间单位
Lu55,2015年

如果考虑到高性能,则应注意这Environment.TickCount要快得多。此处的基准(blog.tedd.no/2015/08/17/…)显示以下相对时间:Environment.TickCount:7ms,DateTime.Now.Ticks:1392ms,Stopwatch.ElapsedMilliseconds:933ms
Special Sauce'Apr

@SpecialSauce,但请注意它们不是等效的东西。另请注意,在我的系统上,Stopwatch.ElapsedMilliseconds它的速度比他的系统快35倍,而我的系统Environment.TickCount仅快2倍。您的硬件可能(显然)有所不同。
马克


7

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();
}

向我+1,因为这是我想知道的。如果有人正在阅读:为什么这个答案没有评论,没有其他上/下投票?(截至2017年5月5日)如果有不正确的地方,请发表评论,如果您认为这是正确的,请投票。
Philm

我已经扩展了基准,请参阅我的答案。顺便说一句,如果您在发布或调试模式下执行这些基准测试,则会有一些有趣的区别(后者可能不应该针对“真实”结果执行,但是很有趣的是,哪些测试是由编译器真正优化的,而哪些则没有)。
Philm

7

以下是此线程中最有用的答案和注释以及其他基准和变体的更新和刷新的摘要:

首先要注意的是:正如其他人在评论中指出的那样,最近几年发生了变化,使用“现代” Windows(Win XP ++)和.NET,以及现代硬件,没有或几乎没有理由不使用Stopwatch()。有关详细信息,请参见MSDN。报价单:

“ QPC精度是否受电源管理或Turbo Boost技术引起的处理器频率变化的影响?
否。如果处理器的TSC不变,,则QPC不受这些变化的影响。如果处理器的TSC不变, QPC将恢复为平台硬件计时器,不受处理器频率变化或Turbo Boost技术的影响。

QPC是否可以在多处理器系统,多核系统以及具有超线程的系统上可靠地工作?

如何确定并验证QPC在我的计算机上可以正常工作?
您无需执行此类检查。

哪些处理器具有不变的TSC?[..进一步阅读..]“

但是,如果您不需要Stopwatch()的精度,或者至少想要确切了解Stopwatch的性能(静态与基于实例)以及其他可能的变体,请继续阅读:

我从cskwg手中接管了上述基准测试,并扩展了代码以使用更多变体。我已经在VS 2017上使用过几年的i7 4700 MQ和C#7进行了测量(更精确地说,是使用.NET 4.5.2编译的,尽管使用了二进制文字,但它还是C#6(用于:字符串文字和“使用静态')。与上述基准相比,特别是Stopwatch()的性能似乎有所提高。

这是一个循环中进行一千万次重复的结果的示例,一如既往,绝对值并不重要,但是即使相对值在其他硬件上也可能有所不同:

32位,发布模式,无优化:

测量值:GetTickCount64()[ms]:275
测量值:Environment.TickCount [ms]:45
测量值:DateTime.UtcNow.Ticks [ms]:167
测量值:秒表:.ElapsedTicks [ms]:277
测量值:秒表:.ElapsedMilliseconds [ ms]:548
测量:静态Stopwatch.GetTimestamp [ms]:193
测量:秒表+转换为DateTime [ms]:551
与DateTime.Now.Ticks比较[ms]:9010

32位,发布模式,已优化:

测量值:GetTickCount64()[ms]:198
测量值:Environment.TickCount [ms]:39
测量值:DateTime.UtcNow.Ticks [ms]:66 (!)
测量值:秒表:.ElapsedTicks [ms]:175
测量值:秒表: .ElapsedMilliseconds [ms]:491
测量:静态Stopwatch.GetTimestamp [ms]:175
测量:Stopwatch +转换为DateTime [ms]: 510
与DateTime.Now.Ticks比较[ms]:8460

64位,发布模式,未经优化:

测量值:GetTickCount64()[ms]:205
测量值:Environment.TickCount [ms]:39
测量值:DateTime.UtcNow.Ticks [ms]:127
测量值:秒表:.ElapsedTicks [ms]:209
测量值:秒表:.ElapsedMilliseconds [ ms]:285
测量:静态Stopwatch.GetTimestamp [ms]:187
测量:秒表+转换为DateTime [ms]:319
与DateTime.Now.Ticks比较[ms]:3040

64位,发布模式,已优化:

测量值:GetTickCount64()[ms]:148
测量值:Environment.TickCount [ms]:31 (是否仍然值得?)
测量值:DateTime.UtcNow.Ticks [ms]:76 (!)
测量值:秒表:.ElapsedTicks [ ms]:178
测量:秒表:.ElapsedMilliseconds [ms]:226
测量:静态Stopwatch.GetTimestamp [ms]:175
测量:秒表+转换为DateTime [ms]:246
与DateTime.Now.Ticks [ms]进行比较: 3020

可能很有趣的是,创建DateTime值以打印出秒表时间似乎几乎没有任何花费。与实际相比,更具学术性的有趣之处在于静态秒表的速度稍快(如预期)。一些优化点非常有趣。例如,我无法解释为什么只有32位的Stopwatch.ElapsedMilliseconds与其其他变体(例如静态变体)相比如此慢。这和DateTime.Now现在的速度是64位的两倍多。

您会看到:仅对于数百万次执行,秒表的时间开始变得重要。如果确实是这种情况(但要提防微优化为时过早),那么使用GetTickCount64()(尤其是使用DateTime.UtcNow)可能会很有趣,您有一个64位(长)的计时器,精度比秒表低,但速度更快,这样您就不必弄乱32位的“丑陋” Environment.TickCount。

不出所料,DateTime.Now是迄今为止最慢的。

如果您运行它,代码还将检索您当前的秒表精度以及更多信息。

这是完整的基准代码:

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;

[...]

    [DllImport("kernel32.dll") ]
    public static extern UInt64 GetTickCount64(); // Retrieves a 64bit value containing ticks since system start

    static void Main(string[] args)
    {
        const int max = 10_000_000;
        const int n = 3;
        Stopwatch sw;

        // Following Process&Thread lines according to tips by Thomas Maierhofer: https://codeproject.com/KB/testing/stopwatch-measure-precise.aspx
        // But this somewhat contradicts to assertions by MS in: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#Does_QPC_reliably_work_on_multi-processor_systems__multi-core_system__and_________systems_with_hyper-threading
        Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); // Use only the first core
        Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
        Thread.CurrentThread.Priority = ThreadPriority.Highest;
        Thread.Sleep(2); // warmup

        Console.WriteLine($"Repeating measurement {n} times in loop of {max:N0}:{NewLine}");
        for (int j = 0; j < n; j++)
        {
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var tickCount = GetTickCount64();
            }
            sw.Stop();
            Console.WriteLine($"Measured: GetTickCount64() [ms]: {sw.ElapsedMilliseconds}");
            //
            //
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var tickCount = Environment.TickCount; // only int capacity, enough for a bit more than 24 days
            }
            sw.Stop();
            Console.WriteLine($"Measured: Environment.TickCount [ms]: {sw.ElapsedMilliseconds}");
            //
            //
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var a = DateTime.UtcNow.Ticks;
            }
            sw.Stop();
            Console.WriteLine($"Measured: DateTime.UtcNow.Ticks [ms]: {sw.ElapsedMilliseconds}");
            //
            //
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var a = sw.ElapsedMilliseconds;
            }
            sw.Stop();
            Console.WriteLine($"Measured: Stopwatch: .ElapsedMilliseconds [ms]: {sw.ElapsedMilliseconds}");
            //
            //
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var a = Stopwatch.GetTimestamp();
            }
            sw.Stop();
            Console.WriteLine($"Measured: static Stopwatch.GetTimestamp [ms]: {sw.ElapsedMilliseconds}");
            //
            //
            DateTime dt=DateTime.MinValue; // just init
            sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < max; i++)
            {
                var a = new DateTime(sw.Elapsed.Ticks); // using variable dt here seems to make nearly no difference
            }
            sw.Stop();
            //Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [s] with millisecs: {dt:s.fff}");
            Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [ms]:  {sw.ElapsedMilliseconds}");

            Console.WriteLine();
        }
        //
        //
        sw = new Stopwatch();
        var tickCounterStart = Environment.TickCount;
        sw.Start();
        for (int i = 0; i < max/10; i++)
        {
            var a = DateTime.Now.Ticks;
        }
        sw.Stop();
        var tickCounter = Environment.TickCount - tickCounterStart;
        Console.WriteLine($"Compare that with DateTime.Now.Ticks [ms]: {sw.ElapsedMilliseconds*10}");

        Console.WriteLine($"{NewLine}General Stopwatch information:");
        if (Stopwatch.IsHighResolution)
            Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
        else
            Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");

        double freq = (double)Stopwatch.Frequency;
        double ticksPerMicroSec = freq / (1000d*1000d) ; // microsecond resolution: 1 million ticks per sec
        Console.WriteLine($"- Stopwatch accuracy- ticks per microsecond (1000 ms): {ticksPerMicroSec:N1}");
        Console.WriteLine(" (Max. tick resolution normally is 100 nanoseconds, this is 10 ticks/microsecond.)");

        DateTime maxTimeForTickCountInteger= new DateTime(Int32.MaxValue*10_000L);  // tickCount means millisec -> there are 10.000 milliseconds in 100 nanoseconds, which is the tick resolution in .NET, e.g. used for TimeSpan
        Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
        // this conversion from seems not really accurate, it will be between 24-25 days.
        Console.WriteLine($"{NewLine}Done.");

        while (Console.KeyAvailable)
            Console.ReadKey(false);
        Console.ReadKey();
    }


0

我使用Environment.TickCount是因为:

  1. Stopwatch类不在Compact Framework中。
  2. 秒表使用与TickCount相同的基础计时机制,因此结果不会或多或少准确。
  3. TickCount的环绕问题在宇宙上不太可能发生(您必须让计算机运行27天,然后尝试测量恰好跨越环绕时刻的时间),即使您确实击中它,结果将是一个巨大的负时间跨度(因此会脱颖而出)。

话虽如此,我也建议您使用秒表(如果有)。或者,您可能需要花费大约1分钟的时间,编写一个类似Stopwatch的类,其中包含Environment.TickCount。

顺便说一句,在秒表文档中,我什么都没有提到底层计时器机制的环绕问题,因此,发现秒表也遇到同样的问题不会让我感到惊讶。但是,我不会再花时间担心它了。


2
#3确实不对,马修斯的答案有更好的解释。这不是围绕折回线的相对时间,只有当您测量的时间超过二十多天时,折回线才是问题。
SoftMemes

1
#3甚至是完全错误的,如果您在服务器上甚至在终端服务器上运行可用作服务的任何内容,这都是一个很大的问题。甚至连我的家用计算机有时也可以在不重启的情况下运行两个月或更长时间(不知道待机状态和休眠状态如何起作用,但是我怀疑它们不会重置它们)。
Lucero 2010年

@Lucero和Freed:无论如何,您绝对应该使用Stopwatch(或TickCount就此而言)测量时间跨度。尽管粒度很高,Stopwatch但长期精度却很差,每天下降多达5-10秒(而不是毫秒)。
MusiGenesis

当我的算法挂起时,我只是被包裹缠住了。该PC运行/休眠超过24天。真讨厌
usr

1
当然可以!我想分享,这样其他人就不会被它咬住。
usr

0

我原本打算将其包装成秒表类,但是Grzenio已经说了对的话,所以我会给他提个醒。这种封装排除了关于哪种方法更好的决定,并且这可能会随时间变化。我记得在某些系统上花费很多时间感到震惊,因此拥有一个可以实施最佳技术的场所非常重要。


0

对于一键式计时,编写起来甚至更加简单

Stopwatch stopWatch = Stopwatch.StartNew();
...dostuff...
Debug.WriteLine(String.Format("It took {0} milliseconds",
                              stopWatch.EllapsedMilliseconds)));

鉴于ElapsedTicks字段很长,我想对于TickCount来说,在宇宙中不太可能出现的环绕问题甚至不会引起更多关注。在我的机器上,秒表是高分辨率的,每秒2.4e9滴答。即使以这样的速度,滴答声字段溢出也将花费121年以上。当然,我不知道幕后到底是怎么回事,所以要加些盐。但是,我注意到StopWatch的文档甚至都没有提到环绕问题,而TickCount的文档却没有。


0

溢流补偿

如前所述,过渡可能会在24.9天后发生,或者,如果使用uint cast,则可能会在49.8天后发生。因为我不想pInvoke GetTickCount64,所以我写了这个溢出补偿。示例代码使用“字节”保持数字方便。请查看一下,它仍然可能包含错误:

using System;
namespace ConsoleApp1 {
    class Program {
        //
        static byte Lower = byte.MaxValue / 3;
        static byte Upper = 2 * byte.MaxValue / 3;
        //
        ///<summary>Compute delta between two TickCount values reliably, because TickCount might wrap after 49.8 days.</summary>
        static short Delta( byte next, byte ticks ) {
            if ( next < Lower ) {
                if ( ticks > Upper ) {
                    return (short) ( ticks - ( byte.MaxValue + 1 + next ) );
                }
            }
            if ( next > Upper ) {
                if ( ticks < Lower ) {
                    return (short) ( ( ticks + byte.MaxValue + 1 ) - next );
                }
            }
            return (short) ( ticks - next );
        }
        //
        static void Main( string[] args ) {
            // Init
            Random rnd = new Random();
            int max = 0;
            byte last = 0;
            byte wait = 3;
            byte next = (byte) ( last + wait );
            byte step = 0;
            // Loop tick
            for ( byte tick = 0; true; ) {
                //
                short delta = Delta( next, tick );
                if ( delta >= 0 ) {
                    Console.WriteLine( "RUN: last: {0} next: {1} tick: {2} delta: {3}", last, next, tick, delta );
                    last = tick;
                    next = (byte) ( last + wait );
                }
                // Will overflow to 0 automatically
                step = (byte) rnd.Next( 0, 11 );
                tick += step;
                max++; if ( max > 99999 ) break;
            }
        }
    }
}

我没有测量和比较该补偿算法的性能。
cskwg

0

TickCount64

我对此新功能进行了一些快速测量,发现(优化,发布64位,1000mio循环):

Environment.TickCount: 2265
Environment.TickCount64: 2531
DateTime.UtcNow.Ticks: 69016

未优化代码的测量结果相似。测试代码:

static void Main( string[] args ) {
    long start, end, length = 1000 * 1000 * 1000;
    start = Environment.TickCount64;
    for ( int i = 0; i < length; i++ ) {
        var a = Environment.TickCount;
    }
    end = Environment.TickCount64;
    Console.WriteLine( "Environment.TickCount: {0}", end - start );
    start = Environment.TickCount64;
    for ( int i = 0; i < length; i++ ) {
        var a = Environment.TickCount64;
    }
    end = Environment.TickCount64;
    Console.WriteLine( "Environment.TickCount64: {0}", end - start );
    start = Environment.TickCount64;
    for ( int i = 0; i < length; i++ ) {
        var a = DateTime.UtcNow.Ticks;
    }
    end = Environment.TickCount64;
    Console.WriteLine( "DateTime.UtcNow.Ticks: {0}", end - start );
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.