2

システムクロック(00:01:00、00:02:00、00:03:00など)と同期して毎分タイマーを実行しようとしています。これは私のコードです。

private System.Timers.Timer timer;

public frmMain()
{
    timer = new System.Timers.Timer();
    timer.AutoReset = false;
    timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    timer.Interval = GetInterval();
    timer.Start();
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{

        System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString("hh:mm:ss tt"));
            timer.Interval = GetInterval();
            timer.Start();

}
private double GetInterval()
{
    DateTime now = DateTime.Now;
    return ((60 - now.Second) * 1000 - now.Millisecond);
}

自宅のPCで問題なく動きます。

12:12:00 AM
12:13:00 AM
12:14:00 AM
12:15:00 AM
12:16:00 AM
12:17:00 AM
12:18:00 AM
12:19:00 AM
12:20:00 AM
12:21:00 AM

しかし、VPS (windows server 2003) で奇妙な結果が得られます。

12:11:59 AM
12:12:59 AM
12:13:00 AM
12:13:59 AM
12:14:00 AM
12:14:59 AM
12:15:00 AM
12:15:59 AM
12:16:00 AM
12:16:59 AM
12:17:00 AM
12:17:59 AM
12:18:00 AM
12:18:59 AM
12:19:00 AM
12:19:59 AM
12:20:00 AM
12:20:59 AM
12:21:00 AM

Windows Server 2003 で System.Timers.Timer がうまく動作しないためでしょうか。それとも私のVPSの問題ですか?

4

5 に答える 5

2

のような通常のタイマーSystem.Timers.Timerは正確ではなく、1 ミリ秒間隔を達成するには十分ではありません。

まず、10 ~ 15 ミリ秒の内部更新レートがあります。第二に、システムによっては、他のスレッドが ~15 ミリ秒実行され、Windows がそれらを強制的に放棄する前にタイマーを遅らせることがあります。

別のスレッドで報告されているタイマーの使用よりも精度が必要な場合はSystem.Diagnostics.Stopwatch、0.3 ミリ秒から使用でき、.NET 環境に統合されます。

もう 1 つのオプションは、マルチメディア時間 (約 1 ミリ秒の精度) を使用することです。

いずれにしても、この問題に関する優れたチュートリアルが ここにあります。

それを分解する:

タイマーのドリフトは通常、タイマーに遅延を追加します。しかし、あなたは反対のことが起こるのを見ています。タイマーはミリ秒の精度を持たないため (15 ミリ秒の範囲でのみ正確です)、多くの場合、その粒度で起動されます。そのため、場合によっては分マークの数ミリ秒前にタイマーを起動します(その後すぐに起動することもあります)。新しい分にのみ起動する必要がある場合は、補正するために数ミリ秒の待機時間を追加します (5 ミリ秒で実行する必要があります)。

自宅の PC はそれほど高速ではなく (つまり、タイマー ハンドラーを処理する余分なタイマー ドリフトが発生することを意味します)、通常は次の 1 秒でイベントを発生させます。あなたの仕事用 PC は、59 秒経過したことを記録するのに十分な速さでタイマー イベントを処理することがあります (これは切り捨てられ、おそらく 59.900 ~ 59.999 であると思います)。これは、マシンがマルチコアの場合にも発生する可能性があります。これは、スレッド生成の遅延がなく、タイマーを非常に迅速に開始できるためです。

それがタイマーの不規則性の原因です。

于 2012-06-15T16:28:26.783 に答える
2

((60 - now.Second) * 1000 - now.Millisecond)

これは、now.Second がたまたま 59 の場合、1 秒以内に再び時間が発生することを意味します。これが奇妙な結果の理由です (タイマーが正確に 0 秒のオフセットで起動しない)。

おそらく、タイマーを毎秒起動させ、前の日付/時刻の値を別の変数に保持し、2 番目の部分が変化したときに画面上のタイマーを更新する方が生産的です。

于 2012-06-15T16:36:40.367 に答える
2

DateTime.Now を使用して個々のパーツをプルする代わりに、Ticksを使用してください。開始時にティックを取得し、次のタイマー ティックのティックを計算します。そのタイマーティックが発生したら、最後の値を使用して次の値を計算します。

    private const long MILLISECOND_IN_MINUTE = 60 * 1000;
    private const long TICKS_IN_MILLISECOND = 10000;
    private const long TICKS_IN_MINUTE = MILLISECOND_IN_MINUTE * TICKS_IN_MILLISECOND;

    private System.Timers.Timer timer;
    private long nextIntervalTick;

    public void frmMain()
    {
        timer = new System.Timers.Timer();
        timer.AutoReset = false;
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Interval = GetInitialInterval();
        timer.Start();
    }

    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {

        System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString("hh:mm:ss tt"));
        timer.Interval = GetInterval();
        timer.Start();

    }
    private double GetInitialInterval()
    {
        DateTime now = DateTime.Now;
        double timeToNextMin = ((60 - now.Second) * 1000 - now.Millisecond) + 15;
        nextIntervalTick = now.Ticks + ((long)timeToNextMin * TICKS_IN_MILLISECOND);

        return timeToNextMin;
    }
    private double GetInterval()
    {
        nextIntervalTick += TICKS_IN_MINUTE;
        return TicksToMs(nextIntervalTick - DateTime.Now.Ticks);
    }
    private double TicksToMs(long ticks)
    {
        return (double)(ticks / TICKS_IN_MILLISECOND);
    }

おそらく、あなたのように Seconds と Milliseconds を使用してこれを行うことができます。秘訣は、計算する開始点を 1 つ持つことです (次の分までの秒数を決定するのではなく)。timer_Elapsed のコードの実行に 1 分以上かかる可能性があるなど、元の問題で言及されていない追加の問題がある場合は、これを処理するコードを追加する必要があります。

追加のヘルプが必要な場合は、コメントを残してください。そうでない場合は、正しい答えを選択してください。

于 2012-06-15T16:42:21.597 に答える
-1

Windows Server は既定で、クライアント バージョンよりも進んでバックグラウンド タスクとリソースを共有するように設定されているため、サーバーが多数のバックグラウンド タスクを実行している場合、タイマーの精度が影響を受ける可能性があることに注意してください。

フォアグラウンド タスクを優先するように一時的に変更して、異なる結果が得られるかどうかを確認することができます。設定はシステム コントロール パネルのどこかにあり、「プログラム」と表示されているラジオ ボタンと「バックグラウンド」と表示されている 2 つのラジオ ボタンを探しています。サービス」など。

于 2012-06-15T16:42:35.520 に答える