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、...

也就是说,它是遥不可及的。我们不是在谈论毫秒。这与计时器是否为高分辨率无关,因为报告为真。据我所知,这与处理器亲和力无关,因为我尝试将其设置为 2 个处理器中的每一个。

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

4

2 回答 2

2

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

在我看来,它们似乎以不同的间隔运行。Win7 大约每秒触发一次。XP 看起来可以每 100 毫秒触发一次(缺少一些样本点 - 很难快速读取内容)。

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

于 2011-09-25T09:01:28.773 回答
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
于 2011-09-25T11:21:25.907 回答