2

私は、System.Timers.Timer が独自のスレッドを作成し、(UI スレッドで実行される Windows.Forms.Timer とは対照的に) より正確なタイミングを実行するタスクを実行するために、Microsoft がこのタイプのタイマーを推奨しているという印象を受けました。

以下のコード (私が思うに) は、空のフォームを持つプロジェクトにコピー アンド ペーストできるはずです。私のマシンでは、tmrWork を 1 秒あたり約 60 回より速く動作させることができず、驚くほど不安定です。

Public Class Form1

    Private lblRate As New Windows.Forms.Label
    Private WithEvents tmrUI As New Windows.Forms.Timer
    Private WithEvents tmrWork As New System.Timers.Timer

    Public Sub New()
        Me.Controls.Add(lblRate)

        InitializeComponent()
    End Sub

    Private StartTime As DateTime = DateTime.Now
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) _
        Handles MyBase.Load
        tmrUI.Interval = 100
        tmrUI.Enabled = True
        tmrWork.Interval = 1
        tmrWork.Enabled = True
    End Sub

    Private Counter As Integer = 0
    Private Sub tmrUI_Tick(sender As Object, e As System.EventArgs) _
        Handles tmrUI.Tick
        Dim Secs As Integer = (DateTime.Now - StartTime).TotalSeconds
        If Secs > 0 Then lblRate.Text = (Counter / Secs).ToString("#,##0.0")
    End Sub

    Private Sub tmrWork_Elapsed(sender As Object, e As System.Timers.ElapsedEventArgs) _
        Handles tmrWork.Elapsed
        Counter += 1
    End Sub
End Class

この特定の単純なケースでは、すべてを tmrUI に配置しても同じパフォーマンスが得られます。System.Timers.Timer を高速化しすぎようとしたことは一度もないと思いますが、このパフォーマンスは私にはあまりにも悪いように見えます。ハードウェアで高性能タイマーを使用する独自のクラスを作成しましたが、1 秒あたり 100 ティックと言うことができる組み込みタイマーが必要なようです。

何が起きてる?

4

1 に答える 1

-1

100Hz に近づけるには、AutoResetEvent を使用するこのようなものを試してください。

Private Sub tmrWork()
    'start this as a background thread
    Dim tmr As New Threading.AutoResetEvent(False)
    Dim stpw As Stopwatch = Stopwatch.StartNew
    Const interval As Integer = 10 'the interval
    '
    '
    Do 'timer
        stpw.Stop()
        If stpw.ElapsedMilliseconds > interval Then
            tmr.WaitOne(interval) 'the interval
        Else
            tmr.WaitOne(CInt(interval - stpw.ElapsedMilliseconds)) 'the interval
        End If
        stpw.Restart()
        '
        'code to execute when 'timer' elapses
        '

    Loop
End Sub

これは、ループで何をするかに応じて、100Hz でコードを起動できることを示すテストです。

Private Sub tmrWork()
    Dim tmr As New Threading.AutoResetEvent(False)
    Dim stpw As Stopwatch = Stopwatch.StartNew
    Const interval As Integer = 10 'the interval
    'for testing
    Dim cts As New List(Of Long)
    '
    '
    Do 'timer
        tmr.WaitOne(interval) 'wait for the interval
        cts.Add(stpw.ElapsedMilliseconds) 'add elapsed to list
        stpw.Restart() 'restart
        If cts.Count >= 500 Then 'five second test
            Debug.WriteLine(String.Format("Avg: {0},  Min: {1},  Max: {2}", cts.Average, cts.Min, cts.Max))
            Stop
        End If
    Loop
End Sub

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim t As New Threading.Thread(AddressOf tmrWork)
    t.IsBackground = True
    t.Start()
End Sub

ハンス・ピサントのために

プラットフォーム タイマーの解像度:プラットフォーム タイマーの解像度 デフォルトのプラットフォーム タイマーの解像度は 15.6 ミリ秒 (15625000 ナノ秒) で、システムがアイドル状態のときはいつでも使用する必要があります。タイマーの分解能を上げると、プロセッサの電源管理テクノロジが効果的でなくなる可能性があります。タイマーの解像度は、マルチメディアの再生またはグラフィック アニメーションによって増加する場合があります。現在のタイマー分解能 (100ns 単位) 100000 最大タイマー期間 (100ns 単位) 156001

Platform Timer Resolution:Outstanding Timer Request プログラムまたはサービスが、プラットフォームの最大タイマー分解能より小さいタイマー分解能を要求しました。要求期間 100000 要求プロセス ID 452 要求プロセス パス \Device\HarddiskVolume3\Windows\System32\svchost.exe

于 2013-10-24T17:51:55.580 に答える