XP 中的 Diagnostics.StopWatch 时间滞后,但 Win7 中没有

发布于 2024-12-06 22:08:35 字数 1119 浏览 0 评论 0原文

ETA:使用Environment.TickCount 不会出现同样的问题。
ETA2:我应该补充一点,我实际上并没有在我的应用程序中使用 Forms.Timer - 因为这会 否定使用高频定时器。我在这里使用它来简化代码。

ETA3:我已经发布了一个解决方法作为下面的答案。

我在使用 XP 的笔记本电脑上观察到 StopWatch 类的问题,但在使用 Win7 的其他笔记本电脑上却没有观察到。这是测试代码:

Public Class FormTest
    Inherits Form

    Private WithEvents Timer1 As System.Windows.Forms.Timer = New System.Windows.Forms.Timer
    Private sw As Stopwatch = New Stopwatch

    Public Sub New()
        Me.Timer1.Interval = 1
    End Sub

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyBase.OnClick(e)
        Me.sw.Start()
        Me.Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Me.Text = sw.ElapsedMilliseconds.ToString
        Me.Update()
    End Sub

End Class

在 Windows 7 上,每秒检查经过的毫秒数,我得到类似以下内容的信息: 0、1010、2030、3005 ...
在 XP 上,我得到的结果如下:0、200、306、390、512……

也就是说,相差甚远。我们不是在谈论毫秒。 这与计时器是否高分辨率无关,因为报告为真。作为 据我所知,这与处理器亲和力无关,因为我已经尝试将其设置为两个处理器中的每一个。

正如我所说,我认为这与 XP 有关,但也可能与不同的内核有关 - 然而,两台笔记本电脑都是英特尔的。

ETA: Using Environment.TickCount does not present the same problem.
ETA2: I should add that I don't actually use the Forms.Timer in my app - as this would
negate the use of a high frequency timer. I've used it here to simplify the code.

ETA3: I've published a workaround as an answer below.

I'm having problems with the StopWatch class that I'm observing on a laptop with XP but not a different laptop with Win7. Here's the test code:

Public Class FormTest
    Inherits Form

    Private WithEvents Timer1 As System.Windows.Forms.Timer = New System.Windows.Forms.Timer
    Private sw As Stopwatch = New Stopwatch

    Public Sub New()
        Me.Timer1.Interval = 1
    End Sub

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyBase.OnClick(e)
        Me.sw.Start()
        Me.Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Me.Text = sw.ElapsedMilliseconds.ToString
        Me.Update()
    End Sub

End Class

On windows 7, checking the ellapsed milliseconds every second, I get something like:
0, 1010, 2030, 3005 ...
On XP, I get something like: 0, 200, 306, 390, 512, ...

That is, it is way off. We're not talking about milliseconds.
It's nothing to do with whether the timer is high resolution, as that reports as true. As
far as I know it's nothing to do with processor affinity as I've tried setting that to each of the 2 processors.

As I say, I think this is to do with XP, but it could be to do with the different cores - both laptops are, however, intel.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

水水月牙 2024-12-13 22:08:35

您是否在任何地方设置计时器的间隔?

在我看来,他们的跑步时间间隔不同。 Win7大概每秒都会被触发一次。 XP 看起来可以每 100 毫秒触发一次(错过了一些样本点 - 很难这么快地读取内容)。

我找不到任何有关默认计时器间隔的文档。如果它没有记录,则可能已在您的计算机之间的操作系统和 .NET 框架版本之间进行了更改。

Do you set the interval of the timer anywhere?

To me it looks like they are running with different intervals. The Win7 is roughly fired every second. The XP one looks like it could be fired every 100ms (with a few sample points missed - it's hard to read things that fast).

I can't find any documentation on the default timer interval. If it is undocumented, it could have been changed between OS and .NET framework versions between your machines.

楠木可依 2024-12-13 22:08:35

我已经通过使用 timeGetTime 方法解决了这个问题。下面的代码是
基本上是 Diagnostics.StopWatch 类,但将 QueryPerformanceCounter 调用替换为 timeGetTime

我还没有完全测试它*但是,从我读到的内容来看,我应该能够打电话给
TimeBeginPeriod(1) 实现与框架秒表一致的分辨率。

(*如果现在已经对其进行了全面测试并且它确实达到了毫秒精度)。

如果有人可以告诉我如何使 QueryPerformanceCounter 在 XP 上工作(如果 XP 确实是问题所在),或者检测是否存在问题,我将取消标记并将您的标记为答案。

Imports System.Runtime.InteropServices

Friend Class StopWatch

    Private Elapsed As Integer
    Private StartTimeStamp As Integer

    Public Sub Start()
        If Not Me._IsRunning Then
            Me.StartTimeStamp = StopWatch.timeGetTime
            Me._IsRunning = True
        End If
    End Sub

    Public Sub [Stop]()
        If Me.isRunning Then
            Me.Elapsed = (Me.Elapsed + (StopWatch.timeGetTime - Me.StartTimeStamp))
            Me._IsRunning = False
            If (Me.Elapsed < 0) Then
                Me.Elapsed = 0
            End If
        End If
    End Sub

    Public Sub Reset()
        Me.Elapsed = 0
        Me._IsRunning = False
        Me.StartTimeStamp = 0
    End Sub

    Private _IsRunning As Boolean
    Public ReadOnly Property IsRunning() As Boolean
        Get
            Return Me._IsRunning
        End Get
    End Property

    Public ReadOnly Property ElapsedMilliseconds() As Integer
        Get
            Dim elapsed = Me.Elapsed
            If Me._IsRunning Then
                elapsed = (elapsed + (StopWatch.timeGetTime - Me.StartTimeStamp))
            End If
            Return elapsed
        End Get
    End Property

    <DllImport("winmm.dll", SetLastError:=True)> _
    Private Shared Function timeGetTime() As Integer
    End Function

End Class

I've solved the problem by using the timeGetTime method instead. The following code is
basically the Diagnostics.StopWatch class but with the QueryPerformanceCounter call replaced with timeGetTime.

I haven't fully tested it yet* but, from what I've read, I should be able to make a call to
TimeBeginPeriod(1) to achieve resolution in line with the framework stopwatch.

(*If have fully tested it now and it does achieve millisecond accuracy).

If anyone can tell me how to make QueryPerformanceCounter work for XP (if indeed XP is the problem), or detect if there is a problem, I'll un-mark this and mark yours as the answer.

Imports System.Runtime.InteropServices

Friend Class StopWatch

    Private Elapsed As Integer
    Private StartTimeStamp As Integer

    Public Sub Start()
        If Not Me._IsRunning Then
            Me.StartTimeStamp = StopWatch.timeGetTime
            Me._IsRunning = True
        End If
    End Sub

    Public Sub [Stop]()
        If Me.isRunning Then
            Me.Elapsed = (Me.Elapsed + (StopWatch.timeGetTime - Me.StartTimeStamp))
            Me._IsRunning = False
            If (Me.Elapsed < 0) Then
                Me.Elapsed = 0
            End If
        End If
    End Sub

    Public Sub Reset()
        Me.Elapsed = 0
        Me._IsRunning = False
        Me.StartTimeStamp = 0
    End Sub

    Private _IsRunning As Boolean
    Public ReadOnly Property IsRunning() As Boolean
        Get
            Return Me._IsRunning
        End Get
    End Property

    Public ReadOnly Property ElapsedMilliseconds() As Integer
        Get
            Dim elapsed = Me.Elapsed
            If Me._IsRunning Then
                elapsed = (elapsed + (StopWatch.timeGetTime - Me.StartTimeStamp))
            End If
            Return elapsed
        End Get
    End Property

    <DllImport("winmm.dll", SetLastError:=True)> _
    Private Shared Function timeGetTime() As Integer
    End Function

End Class
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文