-1

最近、ファイルの後ろに不適切なログを記録していた Windows アプリケーションの解決策を探しています。フォームの回答で与えられた可能性のあるヒントに基づいてサンプルアプリケーションを作成しました....

これがサンプルコードとその出力です....

private Timer tmr = new Timer();
private Stopwatch ss;

void tmr_Tick( object sender, EventArgs e )
{
     WriteData();
}

private void button1_Click( object sender, EventArgs e )
{
     ss = new Stopwatch();
     ss.Start();
     tmr.Interval = 1;
     tmr.Tick += new EventHandler( tmr_Tick );
     tmr.Start();
     WriteData();
}
void WriteData()
{
     Console.WriteLine(ss.ElapsedMilliseconds);
}

出力: 0 19 29 49 69 79 99 109 122 142 162 172 192 202 222 232 252 282 272 294 314 334 341

このコードの精度を高めるにはどうすればよいですか....????

4

2 に答える 2

3
 tmr.Interval = 1;

それは小さな数であり、それを小さくすることができないという利点があります。しかし、いいえ、タイマーが 1 秒間に 1000 回作動することはありません。Timer が Tick イベントを発生させる実際のレートを決定する 3 つの要因があります。

  • UI スレッドが他の処理を実行するのにどれだけビジーか。Click イベント ハンドラーの実行やウィンドウの描画と同様です。Tick イベント ハンドラーは、UI スレッドが何もビジーでない場合にのみ実行できます。アイドル状態である必要があります。. もちろん、これは非常に変動する数値であり、アプリのユーザーが何をしているかに大きく関係します。アプリのウィンドウのサイズ変更など、彼ができることにはかなりのコストがかかります。ペイントなどの一般的な UI スレッドの処理には、数ミリ秒かかります。人間の目には十分な速さですが、Tick イベントを頻繁に実行する必要がある場合は非常に目立ちます。UI が複雑な場合は、数百ミリ秒かかる可能性があります。これを回避するには、別の種類の Timer クラス (System.Threading.Timer または System.Timers.Timer) が必要です。これらは、スレッドプール スレッドでコードを実行するタイマー クラスです。UI スレッドで何が起こっているかによって遅延しないという利点があります。そして、そのコードで何をするかに非常に注意しなければならないという重大な欠点は、確かにできます。

  • マシンが他のことをしている様子。別のプロセスまたはデバイス ドライバーのスレッドを実行するようなものです。これはオペレーティング システムの主要なタスクであり、数百のスレッドがプロセッサを共有できるようにします。Windows のスレッド スケジューラは、スレッドがいつ実行されるかを決定します。プロセッサを取得して実行すると、クォンタムと呼ばれる期間、しばらく実行できます。典型的なクォンタムは、フォアグラウンドのウィンドウが所有するスレッドの 45 ミリ秒です。他のスレッドは、実行する機会が得られるまで中断されます。もちろん、これは Tick イベントを 1 秒間に 1000 回実行する計画に破滅をもたらします。マシン上で実行される他のプログラムを注意深く制御する必要があります。メニーコア プロセッサが大いに役立ちます。

  • Windows がタイマーを更新する頻度。これに関連するコア オペレーティング システム機能は、クロック割り込みです。多くのことに使用され、オペレーティング システムの基本的なハートビートです。プロセッサーの通常の状態は、何もしていないことであり、電源がオフになっています。クロック ティック割り込みによって停止状態からウェイクアップされ、オペレーティング システムは実行する必要がある作業があるかどうかを確認します。デフォルトの割り込み率は 1 秒あたり 64 回で、15.625 ミリ秒ごとに 1 回です。これはタイマーの精度にも影響します。プロセッサが停止しているときは何も起こりません。したがって、設計上、レートが 1 ミリ秒になることはなく、16 ミリ秒未満になることはありません。

後者の弾丸は確かに最大の問題です。実際、プログラムで割り込み率を変更できます。これには、timeBeginPeriod() winapi 関数への pinvoke 呼び出しが必要です。 この回答はその方法を示しています。また、timeSetEvent() 関数についても言及しています。これは、1 ミリ秒のレートを維持できるという合理的な保証があるタイマーに近づける必要がある関数です。

于 2013-05-24T08:43:56.067 に答える
2

ストップウォッチは内部で Windows パフォーマンス カウンター API を使用しているため、かなり正確である必要があります (パフォーマンス カウンター API は、低いマイクロ秒範囲の分解能を持つとされています)。

ただし、ストップウォッチの不正確さではなく、タイマーのドリフトを実際に測定しているため、テストは無効です。

Timer については、サンプルで System.Windows.Forms.Timer クラスを使用しているようです。これは、正確さの点で優れた選択ではありません。唯一の利点は、UI スレッドで Tick イベントを発生させることです。代わりに System.Threading.Timer クラスを試してみてください - 予想に近い結果が得られるかもしれません (ただし、多少のドリフトはあります)。

var timerCallback = (TimerCallback)(sw => Console.WriteLine(((Stopwatch)sw).Elapsed));
var timerInterval = TimeSpan.FromMilliseconds(1);
var stopwatch = Stopwatch.StartNew();
var timer = new Timer(timerCallback, stopwatch, timerInterval, timerInterval);

結局のところ、ストップウォッチの正確さをテストするのは非常に困難です。なぜなら、より正確ですぐに利用できるものは他にないからです!

于 2013-05-24T06:51:33.660 に答える