.NET System.Diagnostics.Stopwatch问题(返回值太低)

Duc*_*rme 12 .net c# stopwatch

在我的电脑上,秒表的返回值太低了.例如,我指定时为200毫秒Thread.Sleep(1000).该程序应该等待1秒钟.我也测试过ManualResetEvent.WaitOne(1000)并得到了相同的结果.框架2.0和3.0都给出了这种奇怪的行为.我正在运行带有.NET Framework 3.5 SP1的Windows XP SP3.

这是我的测试结果(下面的代码):

1000 ms for DateTime.Now.Ticks
0201 ms for Stopwatch.ElapsedTicks
0142 ms for Stopwatch.ElapsedMilliseconds
0139 ms for Stopwatch.ElapsedTicks after Reset
0264 ms for Stopwatch.ElapsedTicks setting ThreadAffinity
0151 ms for Stopwatch.ElapsedTicks setting ProcessorAffinity (and more)
0371 ms for Stopwatch.ElapsedTicks with Syncronized object
Done!
Run Code Online (Sandbox Code Playgroud)

// Program.cs文件

class Program
{
    static void Main(string[] args)
    {
        StopWatchTest.Go();
        Console.WriteLine("Done!");
        Console.ReadLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

// StopWatchTest.cs类

internal static class StopWatchTest
{
    public const int SleepTime = 1000;

    public static void Go()
    {
        #region Test #0 with DateTime.Now.Ticks
        long startTick = DateTime.Now.Ticks;
        Thread.Sleep(SleepTime);
        long stopTick = DateTime.Now.Ticks;
        long elapsedDt = (stopTick - startTick) * 100;
        Display((int)(elapsedDt / 1000 / 1000), "DateTime.Now.Ticks");
        #endregion Test #0 with DateTime.Now.Ticks

        Stopwatch watch = Stopwatch.StartNew();
        long frequency = Stopwatch.Frequency;
        double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / frequency;

        #region Test #1 with Stopwatch.ElapsedTicks
        startTick = watch.ElapsedTicks;
        Thread.Sleep(SleepTime);
        stopTick = watch.ElapsedTicks;
        double elapsedSw = (stopTick - startTick) * nanosecPerTick;
        Display((int)(elapsedSw / 1000 / 1000), "Stopwatch.ElapsedTicks");
        #endregion Test #1 with Stopwatch.ElapsedTicks

        #region Test #2 with Stopwatch.ElapsedMilliseconds
        startTick = watch.ElapsedMilliseconds;
        Thread.Sleep(SleepTime);
        stopTick = watch.ElapsedMilliseconds;
        Display((int)(stopTick - startTick), "Stopwatch.ElapsedMilliseconds");
        #endregion Test #2 with Stopwatch.ElapsedMilliseconds

        #region Test #3 with Stopwatch.ElapsedTicks after Reset
        watch.Stop();
        watch.Reset();
        watch.Start();
        startTick = watch.ElapsedTicks;
        Thread.Sleep(SleepTime);
        stopTick = watch.ElapsedTicks;
        elapsedSw = (stopTick - startTick) * nanosecPerTick;
        Display((int)(elapsedSw / 1000 / 1000), "Stopwatch.ElapsedTicks after Reset");
        #endregion Test #3 with Stopwatch.ElapsedTicks after Reset

        #region Test #4 with Stopwatch.ElapsedTicks and ThreadAffinity
        Thread.BeginThreadAffinity();
        startTick = watch.ElapsedTicks;
        Thread.Sleep(SleepTime);
        stopTick = watch.ElapsedTicks;
        elapsedSw = (stopTick - startTick) * nanosecPerTick;
        Display((int)(elapsedSw / 1000 / 1000), "Stopwatch.ElapsedTicks setting ThreadAffinity");
        Thread.EndThreadAffinity();
        #endregion Test #4 with Stopwatch.ElapsedTicks and ThreadAffinity

        #region Test #5 with Stopwatch.ElapsedTicks and ProcessorAffinity (and more)
        const int affinity = 0x0001;
        Process proc = Process.GetCurrentProcess();
        proc.ProcessorAffinity = new IntPtr(affinity);
        proc.PriorityClass = ProcessPriorityClass.High;
        ProcessThreadCollection ptc = proc.Threads;
        foreach (ProcessThread pt in ptc)
        {
            pt.IdealProcessor = 0;
            pt.ProcessorAffinity = new IntPtr(affinity);
        }
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        startTick = watch.ElapsedTicks;
        Thread.Sleep(SleepTime);
        stopTick = watch.ElapsedTicks;
        elapsedSw = (stopTick - startTick) * nanosecPerTick;
        Display((int)(elapsedSw / 1000 / 1000), "Stopwatch.ElapsedTicks setting ProcessorAffinity (and more)");
        #endregion Test #5 with ProcessorAffinity and more

        #region Test #6 with Syncronized object
        elapsedSw = new SyncTimer().Go();
        Display((int)(elapsedSw / 1000 / 1000), "Stopwatch.ElapsedTicks with Syncronized object");
        #endregion Test #6 with Syncronized object
    }

    private static void Display(int milliseconds, string testName)
    {
        Console.WriteLine("{0:0000} ms for {1}", milliseconds, testName);
    }
}

[Synchronization]
internal class SyncTimer : ContextBoundObject
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public double Go()
    {
        Stopwatch.StartNew();
        long frequency = Stopwatch.Frequency;
        double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / frequency;

        long startTick = Stopwatch.GetTimestamp();
        Thread.Sleep(StopWatchTest.SleepTime);
        long stopTick = Stopwatch.GetTimestamp();
        return (stopTick - startTick) * nanosecPerTick;
    }
}
Run Code Online (Sandbox Code Playgroud)

Nia*_*ton 6

看看以下链接:

https://connect.microsoft.com/VisualStudio/feedback/details/94083/stopwatch-returns-negative-elapsed-time

System.Diagnostics.Stopwatch在Elapsed ...属性中返回负数

似乎秒表准确性存在问题,这可能导致它返回负的经过时间,并且也会有很多不同的时间.如果你看看Connect问题,那里的大多数人都在谈论在虚拟机上看到问题,这是我们看到负面Elapsed值问题的地方.

查看QueryPerformanceCounter文档,似乎暗示这个问题可能由于BIOS或硬件抽象层错误而在多处理器系统上发生,但没有提供进一步的信息,也没有具体说明虚拟机.

至于解决这个问题的方法......我在google搜索中找不到一个.您可以忽略小于零的值,这在某些情况下并不理想但可行.但这并不能解决您的问题 - 您如何知道哪些值无效?

希望这有点帮助.


Thi*_*rry 5

我知道这是一个老问题,但我想在解决同样的问题后我会提供 2 美分:

我开始按照@AllonGuralnek的建议查看频率,它确实提供了以秒为单位的准确时间,但它丢失了我也想捕获的剩余毫秒数。

不管怎样,经过多次来回却一无所获,我注意到 sw.Elapsed 有一个 Ticks 属性,这个属性为我提供了准确的刻度数,一旦转换回来,它就为我提供了准确的时间。

就代码而言,这就是我最终得到的结果:

Stopwatch sw = new Stopwatch();
sw.Start();

... DO WORK

sw.Stop();

long elapsedTicks = sw.Elapsed.Ticks;
Debug.WriteLine(TimeSpan.FromTicks(elapsedTicks).ToString());
Run Code Online (Sandbox Code Playgroud)

运行测试时,调用:

  • sw.Elapsed.ToString():“00:00:11.6013029”

  • sw.ElapsedTicks :返回“40692243”,调用时转换为“00:00:04.0692243”,TimeSpan.FromTicks(sw.ElapsedTicks).ToString()不准确。

  • sw.Elapsed.Ticks :返回“116013029”,调用时转换为“00:00:11.6013029” TimeSpan.FromTicks(sw.Elapsed.Ticks).ToString()

虽然我可能遗漏了一些东西,但我觉得 sw.​​ElaspedTicks 返回与 sw.Elapsed.Ticks 不同的值是没有意义的,所以如果有人想阐明这一点,请这样做,但从我的角度来看,我将其视为一个错误,如果不是,至少感觉非常不一致!。

注意:调用sw.ElapsedTicks / Stopwatch.Frequency返回 11(即秒),但正如我所说,它会减少毫秒,这对我来说没有用。


Elr*_*ynn -1

我相信您会在这里找到答案: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/eec73d6e-f597-4342-be48-5d2ce30202f0/

但有关更多详细信息和解释,另请参阅: http://msdn.microsoft.com/en-us/magazine/cc163996.aspx http://stackoverflow.com/questions/394020/stopwatch-accuracy http://msdn.microsoft .com/en-us/library/system.diagnostics.stopwatch.aspx