none
タイマーを正確にミリ秒単位で動かしたい RRS feed

  • 質問

  • ストアアプリで指定されたミリ秒間隔でデータを取る処理を作っています。
    開発環境は VisualStudio2019 でC#を使っています。

    指定された間隔は 10ミリ秒なんですが、
    以下のようなプログラムで得た時刻(timedata)をタイマーをStop後に見たら、30~38ミリ秒間隔位なります。
    (確認は Windows10(64bit版)のPCで行っています)

    // タイマー設定
    DispatcherTimer dispatcherTimer = new DispatcherTimer();
    dispatcherTimer.Tick += dispatcherTimer_Tick;
    dispatcherTimer.Interval = TimeSpan.FromMilliseconds(10)
    timeCnt = 0;
    
    // タイマー起動
    dispatcherTimer.Start();
    
    void dispatcherTimer_Tick(object sender, object e)
    {
       timedata[testCnt++] = DateTime.Now.ToString("yyyyMMddHHmmss.fff");
    }

    TimeSpan.FromMilliseconds(0) にすると12~18ミリ秒間隔位になるのですが、
    デバイスに依存しているようであまり気持ちよくありません。(完成版はタブレットで使う予定です)

    指定したミリ秒間隔である程度正確(1~2ミリ秒の誤差は許容範囲)にタイマーを動かく方法がありましたらご教授お願いします。

    2020年5月1日 4:41

回答

  • 本当にミリ秒単位で動かないといけないのでしょうか?
    多少周期がずれても、キューに貯まるだけでうまく動くなら、その精度を期待しないで作ったら良いと思います。
    ミリ秒単位のシビアな動きを要求されるなら、Windows など搭載した汎用 PC を使うのではなく、特化したデバイスを考える領域になってきます。

    (参考)
    DispatcherTimer は UI スレッドでの動作なので UI スレッド依存で精度は悪い方になります。
    ほかのタイマー(参考)を使っても、高い精度は保証されていないと思います。
    専用スレッドでループをうまく使えば近しい精度になるかもしれませんが、これも保証された動きではないです。

    本当はミリ秒単位のシビアさがなく、今よりも周期の頻度を上げたいだけならバックグラウンド系のタイマー、スレッドを考えるところでしょうね。(その代わり、UI を扱えなくなるので同期周りに苦労しますが)

    2020年5月1日 4:59
    モデレータ

すべての返信

  • 本当にミリ秒単位で動かないといけないのでしょうか?
    多少周期がずれても、キューに貯まるだけでうまく動くなら、その精度を期待しないで作ったら良いと思います。
    ミリ秒単位のシビアな動きを要求されるなら、Windows など搭載した汎用 PC を使うのではなく、特化したデバイスを考える領域になってきます。

    (参考)
    DispatcherTimer は UI スレッドでの動作なので UI スレッド依存で精度は悪い方になります。
    ほかのタイマー(参考)を使っても、高い精度は保証されていないと思います。
    専用スレッドでループをうまく使えば近しい精度になるかもしれませんが、これも保証された動きではないです。

    本当はミリ秒単位のシビアさがなく、今よりも周期の頻度を上げたいだけならバックグラウンド系のタイマー、スレッドを考えるところでしょうね。(その代わり、UI を扱えなくなるので同期周りに苦労しますが)

    2020年5月1日 4:59
    モデレータ
  • FYI
    ------------------------------------------------
    マルチコアCPUの消費電力はスケジューリングで変わる?
    https://ascii.jp/elem/000/000/672/672088/

    一般的なパソコンでは、15.6ミリ秒ごとにCPUに割り込みがかかり、
    そのタイミングでスケジューラー(ディスパッチャー)が動作して、
    より優先順位の高いスレッドがあれば、
    そのスレッドを実行する。
    ------------------------------------------------
    Processes, Threads, and Jobs in the Windows Operating System
    https://www.microsoftpressstore.com/articles/article.aspx?p=2233328
    ------------------------------------------------
    About Multimedia Timers
    https://docs.microsoft.com/en-us/windows/win32/multimedia/about-multimedia-timers
    ------------------------------------------------
    Timer Resolution
    https://docs.microsoft.com/ja-jp/windows/win32/multimedia/timer-resolution
    ------------------------------------------------
    timeGetDevCaps function
    https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timegetdevcaps
    ------------------------------------------------




    • 編集済み お馬鹿 2020年5月1日 5:45
    2020年5月1日 5:28
  • Azuleanさん
    お馬鹿 さん

    ご回答ありがとうございます。

    初期依頼が 1秒間にユーザーが指定したミリ秒間隔で情報が欲しいというものでした。
    これから結果を報告して反応を見る という感じです。

    とりあえず頂いた情報で簡単では無いという事が判りました。
    ありがとうございました。
    2020年5月1日 5:41
  • 15.6msという話もありますが、その前提として一般的なモニタが60fps、つまり1秒間に60回しか画面更新しません。そのために16.6ms単位で処理すれば十分という考え方があり、タイマー精度もそれに基づいています。

    そのため、ミリ秒間隔で情報を取得したとしても表示することができないということを理解すべきです。

    なお、Windowsの各種Timerの精度について調べたことがあります。廃止済みとされているマルチメディアタイマーを使用すれば高い精度が得られるかもしれません。

    2020年5月1日 6:09
  • 佐祐理さん

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

    クライアントにこの機能の精度がどこまで必要か 問い合わせています。

    また判らない事がありましたらよろしくお願いします。

    2020年5月1日 7:47
  • ほかに気になるとしたら「ストアアプリ」と表現している点でしょうか。
    Microsoft Store での公開を目指している場合は、使える API に制限がかかりますので。
    2020年5月1日 8:04
    モデレータ
  • 返信ありがとうございました。

    ストアアプリと書きましたが、ストアには公開しないアプリでした。 APIの制限についてはタメになります。

    2020年5月1日 10:46