C#で一定間隔で繰り返す時の待ち方

環境は.net6.0 C#です。
一定間隔で繰り返し何かをしたいときの書き方をまとめてみます。

まずは、適当に1秒間隔くらいでいい時。

while (true)
{
    DoSomething();

    await Task.Delay(TimeSpan.FromSeconds(1));
}

これで、ループ事に1秒待って実行されます。
さて、なぜ「適当に」なのか。一応説明しておきます。
DoSomethingの実行に、仮に100ミリかかるとします。
1回目の実行を、0秒の時点だとして、次の実行は、0秒+100ミリ秒+1秒で、1.1秒後になります。
DoSomething()の実行時間分、ずるずる遅れていきます。

で次は、正確に1秒間隔で実行したいときです。

DateTime runNext = DateTime.Now;

while (true)
{
    DoSomething();

    runNext = runNext + TimeSpan.FromSeconds(1);

    var waitTimeSpan = runNext - DateTime.Now;
    if (waitTimeSpan > TimeSpan.Zero)
    {
        await Task.Delay(waitTimeSpan);
    }
}

ちょっと面倒になりましたね。
でも、これで1秒毎に実行されるようになります。
DoSomething()に、1秒以上かかるとうまくいかないので、そちらはご注意ください。

おまけで、毎分0秒になったら実行したいというのも書いてみましょう。

// 初回実行は、30秒以上後
// AddSeconds(60)は、秒を切り捨てるので、今より早い時間にならないために。
DateTime tempDateTime = DateTime.Now.AddSeconds(30).AddSeconds(60);

DateTime runNext = new DateTime(tempDateTime.Year, tempDateTime.Month, tempDateTime.Day, tempDateTime.Hour, tempDateTime.Minute, 0);

while(true)
{
    DoSomething();

    runNext = runNext + TimeSpan.FromMinutes(1);

    var waitTimeSpan = runNext - DateTime.Now;
    if (waitTimeSpan > TimeSpan.Zero)
    {
        await Task.Delay(waitTimeSpan);
    }
}

追加:以下で、切り捨てとかの実装を見つけた。
リンク先の実装の方が速くてよさそう。
[C#] DateTime を指定した単位に切り上げ、切り捨て、四捨五入する – ざこノート (dokeep.jp)

投稿日:
カテゴリー: C#

1件のコメント

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です