4

DotNetの代替手段(MONO- http://www.go-mono.com/mono-downloads/download.html)は、短いタイマー条件を適切に処理します(最大12ミリ秒の起動時間)。 「ミス」。では、どの動作が正しいのでしょうか?モノはそのイベントの発火を適切に追跡していますか?、それは間違ったストップウォッチでその数を混乱させていますか?または、DotNetには「レイジー」イベントタイマーがありますか?私のテストでは、明らかに、これは根本的なWindowsの問題ではありません。

.NET 200ms+ Interval minimum

Mono 12ms+ Interval minimum

この問い合わせは次のようになります。タイマーは間隔よりも10ミリ秒長くかかります

ただし、コードを検討してください。

.NETでは、見逃されたイベントはゆっくりと増加します。

Total Runtime/Interval - Actual Events = Missed Events

コード:

class Program
{
    const int Interval = 60; //ms Event fireing

    Stopwatch TotalRunTime = new Stopwatch();//Full runtime.
    Stopwatch Calctime = new Stopwatch(); //Used to load up the Event to 66 percent

    System.Timers.Timer TIMER; //Fireing Event handler.
    int TotalCycles = 0; //Number of times the event is fired.
    int Calcs_per_cycle = 100; // Number of calcs per Event.

    static void Main(string[] args)
    {
        Program P = new Program();
        P.MainLoop();
    }

    void MainLoop()
    {
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        TIMER = new Timers.Timer();
        TIMER.Interval = Interval;
        TIMER.Elapsed += new ElapsedEventHandler(MS_Calc);
        TIMER.AutoReset = true;
        TIMER.Enabled = true; //Start Event Timer
        TotalRunTime.Start(); //Start Total Time Stopwatch;

        while (true)
        {
            Thread.Sleep(Interval * 5);
            Console.Clear();
            PrintAtPos(2, "Missed Events " + (((TotalRunTime.ElapsedMilliseconds / Interval) - TotalCycles).ToString()));

        }

    }
    public void MS_Calc(object source, System.Timers.ElapsedEventArgs E)// public void MS_Calc(object source, ElapsedEventArgs E)
    {
        TotalCycles++;
        Calctime.Start();
        for (int i = 0; i < Calcs_per_cycle; i++)
        {
            int A = 2;
            int B = 2;
            int c = A + B;
        }
        PrintAtPos(1, "Garbge Collections G1: " + GC.CollectionCount(0) + "  G2: " + GC.CollectionCount(1) + "  G3: " + GC.CollectionCount(2) + " ");
        Calctime.Stop();
        if (Interval * 0.667 > Calctime.ElapsedMilliseconds) //only fill the even timer 2/3s 
        //full to make sure we finish before the next event
        {
            Calcs_per_cycle = (int)(Calcs_per_cycle * 1.035);
        }
        Calctime.Reset();
        PrintAtPos(0, "Calc Time : " + (DateTime.Now - E.SignalTime).Milliseconds + "  Calcs/Cycle: " + Calcs_per_cycle);
    }

    private static void PrintAtPos(int Vertical_Pos, string Entry)
    {
        Console.SetCursorPosition(0, Vertical_Pos);
        Console.Write(Entry);
    }
}
4

1 に答える 1

4

問題は、Windows システム クロックが、使用したタイム スケールで正確ではないことです。Microsoft の実装でTimerは、システム クロックを使用してElapsedイベントを発生させるタイミングを決定していると思います。システム クロックの (不正確な) 精度を考慮すると、観測された動作のかなり正確な説明が得られるため、私はこれを想定しています。

システム クロックは 15.6 ミリ秒までしか正確ではありません (理由はバッテリー寿命を維持するためです。この質問を参照してください)。したがって、Elapsedイベントは正確に 60 ミリ秒ごとに発生するのではなく、62.4 ミリ秒ごとに発生します。その 2.4 ミリ秒の差が集計され、「見逃した」イベントがあります。あなたのプログラムを 33009 ミリ秒実行したところ、22 の見逃したイベントが報告されました。私はイベントの違いを期待してい33009 * (1/60 - 1/62.4) = 21.2ます。これは、15.6 ミリ秒の数値をより高い精度で取得できないことを考えると、取得しようとしているのとほぼ同じです。(たとえば、経過時間が 62.5 ミリ秒の場合、予想されるミスは 22.0 になります)。

あなたのサンプルは、フレームワークの実装がより正確になるTimer 可能性があることを確かに示しています。Mono の実装がより正確である理由はわかりませんが、一般的にタイマーは正確なミリ秒単位のタイミング用ではありません。システムクロックよりも正確な他のタイミング方法がありStopwatch、利用可能な場合はクラスで使用されます。

于 2012-12-20T06:11:43.787 に答える