6

私はしばらくの間 C# を使用して小さなゲームを作成してきましたが、別の PC でそのゲームをテストしているときに、奇妙な経過時間の問題に遭遇しました。

ほとんどの場合、最後のゲーム ループから経過した時間に基づいて更新されるように、このゲームですべてを設定しましたが、2 台目の PC ではすべてがうまくいきませんでした。

メソッドを使用して TimeSpan を作成することに問題があることがわかりましたFromTicks()。次のコードを使用して少しテストを行いました。

class Program
{
    static void Main(string[] args)
    {
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
        sw.Stop();
        TimeSpan t = TimeSpan.FromTicks(sw.ElapsedTicks);
        Console.WriteLine(t.ToString());
        Console.WriteLine(sw.Elapsed.ToString());
        Console.ReadKey();
    }
}

メイン PC でこのプログラムを実行したところ、次の結果が得られました。

    00:00:00.3528353
    00:00:00.9856987

私が全く期待していなかった何か。2 番目の結果はかなり不正確だと思いましたが、最初の結果はかなり外れていました。

次に、別の PC で同じプログラムを実行したところ、次の結果が得られました。

    00:03:20.6866734
    00:00:00.998287

私はかなり驚いた。

ここでの私の質問は、この問題をどのように修正できるかではありません。十分に正確であるため、2番目の方法を使用することをすでに決定しています...むしろ、啓発を求めます。

これはどうしてですか?最初の結果がそれほど不正確なのはなぜですか? これが別のマシンで大きく異なるのはなぜですか?

メソッドを間違って使用していた場合に備えてmsdnをチェックしましたが、そこにある例では、私の結果は不可能であることを示しています...

注:
CMOS バッテリーが切れている/死んでいると思いますが、それは要因ですか?

4

3 に答える 3

6

Timespan の Ticks と Stopwatch の Ticks は異なります。調整するには、代わりに Stopwatch Elapsed プロパティを使用します。これは、マシンのティックに基づいて TimeSpan に正しく変換されます。

    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); 
    sw.Start();         
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));         
    sw.Stop();         

    // don't load a TimeSpan with ElapsedTicks, these have diff frequency,
    // call Elapsed instead to get TimeSpan.
    TimeSpan t = sw.Elapsed;         
    Console.WriteLine(t.ToString());         
    Console.ReadKey(); 

または、もちろん自分で周波数などで割ることもできますが、それはより多くの作業です。主なポイントは、TimeSpan の Ticks を Stopwatch の Ticks と同じと見なすべきではないということです。

関連スレッド: Stopwatch.ElapsedTicks で使用される単位であるタイマー ティックとは

于 2011-10-18T15:17:08.923 に答える
6

要約:ストップウォッチの頻度はハードウェアによって異なる場合があります。つまり、ティック (間隔は頻度に基づいています) のサイズが異なります (また、timespan および datetime オブジェクトのティックとはサイズが異なります)。

つまり、Elapsed代わりにプロパティを直接使用します。

    TimeSpan t = sw.Elapsed;

...または、計算を実行する必要がある場合は、のTicksプロパティを使用します。Elapsed

    TimeSpan t = TimeSpan.FromTicks(2*sw.Elapsed.Ticks);

参照付きの長いバージョン:

http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.elapsedticks.aspxは、経過ティックの msdn ページです。注目すべきは:

このプロパティは、基になるタイマー メカニズムの経過ティック数を表します。ティックは、ストップウォッチ タイマーが測定できる時間の最小単位です。Frequency フィールドを使用して、ElapsedTicks 値を秒数に変換します。

そして、Frequency フィールドのページから:

タイマー周波数は、タイマーの精度と分解能を示します。たとえば、1 秒あたり 200 万ティックのタイマー周波数は、1 ティックあたり 500 ナノ秒のタイマー分解能に相当します。つまり、1 秒は 10 億ナノ秒に等しいため、1 秒あたり 200 万ティックのタイマー周波数は、10 億ナノ秒あたり 200 万ティックに相当し、さらに単純化して 500 ナノ秒あたり 1 ティックにすることができます。

Frequency の値は、基礎となるタイミング メカニズムの解像度によって異なります。インストールされているハードウェアとオペレーティング システムが高解像度のパフォーマンス カウンターをサポートしている場合、Frequency 値にはそのカウンターの頻度が反映されます。それ以外の場合、Frequency 値はシステム タイマーの頻度に基づきます。

ストップウォッチの頻度はインストールされているハードウェアとオペレーティング システムに依存するため、システムの実行中は頻度の値は一定のままです。

したがって、基本的にストップウォッチの周波数はハードウェアによって異なる場合があります。つまり、ティックのサイズが異なります (また、timespan および datetime オブジェクトのティックとはサイズが異なります)。

興味深いことに、タイムスパンを提供する Elapsed プロパティ StopWatch を既に使用しています。sw.Elapsed は TimeSpan オブジェクトを取得しようとしているときにおそらく必要になる TimeSpan です。ティックを使用する場合は、代わりにこの TimeSpan の Ticks プロパティを使用できます。

または、long を返す ElapsedMilliseconds を使用できます。

于 2011-10-18T15:17:58.077 に答える