Diagnostics.StopWatch时间滞后在XP但不是Win7

时间:2011-09-25 08:49:41

标签: c# .net vb.net timing stopwatch

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

ETA3:我在下面发表了一个解决方法作为答案。

我遇到了StopWatch类的问题,我在使用XP的笔记本电脑上观察到但没有使用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,......

也就是说,它已经过时了。我们不是在谈论毫秒。 它与定时器是否为高分辨率无关,因为它报告为真。如 据我所知,它与处理器关联性无关,因为我已经尝试将其设置为2个处理器中的每一个。

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

2 个答案:

答案 0 :(得分:2)

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

对我来说,它们似乎以不同的间隔运行。 Win7大致每秒都会被解雇。 XP看起来可能每100毫秒就会被触发一次(错过了几个样本点 - 很难快速读取内容)。

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

答案 1 :(得分:0)

我已经使用 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
相关问题