2010-11-18 6 views
15

可能な限り最高の解像度のタイマーをC#で使いたい。たとえば、私は11ティックごとにイベントを発生させたい(ティックはPCの中で可能な限り最高のカウンターだと聞いた)。私はタイマーを試して、最小経過時間がミリ秒であることを発見しました。ストップウォッチを見ましたが、ストップウォッチはイベントを起こしませんでした。高解像度のインターバル/タイマーでイベントを発生させよう

ありがとうございました。

+2

なぜあなたは11ティックごとにイベントを発生させたいのですか?これをコードプロファイリングに使用していますか? –

+5

あなたは質問に答えていません。 11ティックは単なる例です。私が望むのは高解像度タイマーです。可能であれば、1ティックまで。はい、いくつかのベンチマークを行うためのアプリケーションを開発しています。 –

+0

これは私がコメントをdownvotingをサポートしている理由です –

答えて

18

マルチメディアタイマーを使用すると、約1000件のイベントが発生します。このコードは途中であなたを助けるはずです。

 public delegate void TimerEventHandler(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2); 

    /// <summary> 
    /// A multi media timer with millisecond precision 
    /// </summary> 
    /// <param name="msDelay">One event every msDelay milliseconds</param> 
    /// <param name="msResolution">Timer precision indication (lower value is more precise but resource unfriendly)</param> 
    /// <param name="handler">delegate to start</param> 
    /// <param name="userCtx">callBack data </param> 
    /// <param name="eventType">one event or multiple events</param> 
    /// <remarks>Dont forget to call timeKillEvent!</remarks> 
    /// <returns>0 on failure or any other value as a timer id to use for timeKillEvent</returns> 
    [DllImport("winmm.dll", SetLastError = true,EntryPoint="timeSetEvent")] 
    static extern UInt32 timeSetEvent(UInt32 msDelay, UInt32 msResolution, TimerEventHandler handler, ref UInt32 userCtx, UInt32 eventType); 

    /// <summary> 
    /// The multi media timer stop function 
    /// </summary> 
    /// <param name="uTimerID">timer id from timeSetEvent</param> 
    /// <remarks>This function stops the timer</remarks> 
    [DllImport("winmm.dll", SetLastError = true)] 
    static extern void timeKillEvent( UInt32 uTimerID); 

実行後にこれらのタイマーを停止します。彼らはあなたのシステムでかなり重いです*。すべての例外をキャッチし、イベントハンドラからエスケープさせないでください。

* 5台以上のタイマーを起動すると、ほとんどのシステムが大幅に遅くなります。 イベントハンドラで可能な限り小さなコードを実行し、実行コードが1ミリ秒より速いか重大な問題に直面していることを確認してください。私はラベルの表示を増やすために、10〜50ティックごとに代表者を始めました。

Thread.Sleepで発生する通常のスレッドスイッチでは、スレッドスロットにコードが1つも残らず、約40ミリ秒かかります。いくつかのNTカーネルコールでスレッドスイッチの周波数を上げることもできますが、しないでください。

4

さまざまなタイマークラスは、より細かい粒度を使用します。 Threading.TimerとTimers.Timerは1/64秒を使用します。これは15.625ミリ秒です。

DateTimeクラス、TimeSpanクラスで使用され、Stopwatchによって出力される100ナノ秒の目盛りが参照されている場合、あなたが求めている11ティックの長さは1,100ナノ秒です。 1.1マイクロ秒。私の知る限りでは、その解決策を提供する内蔵タイマーはありません。 1.1マイクロ秒ごとにイベントが発生するようにしたいのであれば、「タイマー」の考え方を取り除かなくてはならず、少し遅れて考える必要があります。スレッドの優先度を高め、イベントをループで実行します。 1.1マイクロ秒はシステムスケジューラのタイムスライスよりも小さいと思うので、Thread.Sleep()を呼び出さないでください。代わりに遅延ループを実行する必要があります。

また、あなたが求めている時間間隔が非常に小さいことを認識してください。 1.1マイクロ秒は、2GHzプロセッサ上でわずか2,200プロセッササイクルである。わずかな量ではありませんが、多くの作業を完了するまでには時間がかかりません。あなたがあなたのコメントで言った1ティックを話しているなら、それはわずか200プロセッササイクルです:それは数十回の数学演算を行うのに十分な時間であり、1つの関数を呼び出すかもしれません。

+0

私に興味があるティックはストップウォッチです。言い換えれば、プロセッササイクルティック。 –

+3

プロセッササイクルティック(例:2GHz)? 0.5ナノ秒です。最も単純なプロセッサ命令を除くすべては、複数のプロセッササイクルをとる。たとえば、あるサイクルで整数をインクリメントできますが、 'if'文はインクリメントできますか?それは10プロセッサ・サイクル、5ナノ秒のオーダーです。その頻度でタイマーをチェックする方法はありませんし、作業が少なくて済みます。 –

+4

待って、私はそれを取り戻す。 1プロセッササイクルの頻度を持つタイマーを持つ方法があります:スレッドを高い優先度に設定し、while(true){...} 'を実行します。 –

14

最初に、ハードウェアとソフトウェアの両方の制限があるため、コンピュータで正確なタイミングをとることは非常に困難ではありますが、不可能ではありません。良いニュースは、この種の精度はめったに必要ありません。 10ダニは、微妙に小さい時間です。この間隔でCPUが処理する作業はほとんどなく、決して統計的に重要ではありません。

参考までに、Windowsクロックの精度は約10ミリ秒(以前のバージョンではそれ以下)です。 DateTime.UtcNowへの呼び出しでコードをラップすることは、それ以上のことはしません。

あなたの質問では、「イベントを起こしたい」と話します。問題は、特定の間隔でイベントを発生させる唯一のタイプの時間保持オブジェクトがTimerオブジェクトであることです。 .NETフレームワーク(System.Timers.TimerSystem.Threading.Timer、およびSystem.Windows.Forms.Timer)の3つの異なるインカネーションで利用できますが、いずれも独自の使用シナリオと相対的な性質を持っていますが、は、 。それらはそうするように設計されておらず、このタイプの精度を提供するWindows APIによって公開される同等の関数もありません。

なぜ私はあなたがこれをやりたいと思っていたのか、それをベンチマークしようとしているのは、それがゲーム全体を変えるからです。 .NET Framework(バージョン2.0以降)は、ベンチマークやパフォーマンスのプロファイリングなどの状況の経過時間を正確に測定できるように明示的に設計されたStopwatch objectを提供します。 Stopwatchは、Windows API関数QueryPerformanceFrequencyQueryPerformanceCounterを単にラップしています(これは私の提案した使用方法を確認するものです)。以前のバージョンのフレームワークでこのタイプの機能にアクセスするには、これらの関数をP/Invokeする必要がありましたが、これは便利な機能です。ベンチマークのために比較的高い解像度のタイマーが必要な場合は、Stopwatchが最適です。理論上、サブマイクロ秒のタイミングを提供することができます。

しかし、問題がないわけではありません。イベントは発生しませんので、現在のデザインがイベント処理に依存している場合は、それを再考する必要があります。また、も完全に正確であるとは限りません。確かに、与えられたハードウェアの制約のなかでの可能な限り最高の解決策があるかもしれませんが、それは必ずしもあなたの規定された要件を満たすことを意味しません。たとえば、同じプロセッサ上でStartとを実行する必要があるマルチプロセッサシステムでは、信頼性が低い可能性があります。それは問題ではないが、it does。クロック速度を上下させることができるプロセッサ上のsubject to being unreliableです。 QueryPerformanceCounterへの呼び出し自体も現代の2GHz以上のプロセッサでも約5マイクロ秒という時間がかかると言いますが、実際には理論的にはうまくいかないサブマイクロ秒のタイミングを達成することができません。次に、合理的なコードプロファイラは、その時間が無視できると考えます。つまり、です。
(参考:http://www.devsource.com/c/a/Techniques/High-Performance-Timing-under-Windows/2/

+0

長引かれた説明に感謝します。たとえば、リアルタイムOSを使用している場合、そのような高精度タイマーを取得できますか? WindowsサーバーリアルタイムOSですか?ありがとう。 –

+2

RTOSを使用している場合は、高解像度タイマーの可能性があります。しかし、リアルタイムOSは、すぐに起こることを意味するのではなく、既知の時間制限内で発生するため、思っているほどの正確な時間を確保できないことがあります。 WindowsはRTOSなので、間違いなく。 –

+1

@publicENEMY:David Yawの応答は正しいです。サーバーのバージョンのWindowsでさえリアルタイムのオペレーティングシステムではありません(私はワークステーションとしてWindows Serverを実行しますが、あまり違いはありません)。 OSによって公開されているソフトウェアの制限を克服しても、一般的なPCハードウェアの限界に挑戦しなければならないということも指摘しておきましょう。 OSの切り替えを検討している場合は、達成しようとしていることを実行するためのより良い方法が必要です。 –

関連する問題