【C#】PeriodicTimerの使い方

相当前に C# には 4つの代表的な記事がありますと記事を書きましたが、最近は UI 以外の場所の処理ではすっかり既存のタイマークラス(Timers.Timer や Threading.Timer)を使わなくなり、大半を PeriodicTimer や自作の async なループで定周期処理を実装するように変わってきました。

アプリケーションレイヤー的な場所では、管理が簡単で余計な考慮事項が少ないため既存のタイマーに代わる新しい定周期処理の実装方法を紹介したいと思います。


以前書いた記事 ↓ ↓

C#の4つのTimerの用途と使い方 - PG日誌


確認環境

この記事は以下の環境で実装・確認しています

  • .NET 8(C# 12)
  • VisualStudio 2022
  • Windows11

PeriodicTimerの使用例

このクラス使用方法が簡単でオブジェクトを new したら ループ中で WaitForNextTickAsync を await で待機するだけです。

public static async Task PeriodicTimerSampleAsync(
    TimeSpan period, CancellationToken ct = default)
{
    using PeriodicTimer timer = new(period); // IDisposableなのでusingを使用する
    try
    {
        Console.WriteLine("Start");

        Stopwatch sw = Stopwatch.StartNew();

        while (await timer.WaitForNextTickAsync(ct)) // ここで一定時間待機
        {
            // やりたいことを書く
            Console.WriteLine($"{sw.Elapsed.TotalMilliseconds}");
            sw.Restart();
        }
    }
    catch (OperationCanceledException)
    {
        // 無視
    }
    finally
    {
        Console.WriteLine("Exit");
    }
}

この処理の使用方法は以下の通りです

static async Task Main(string[] args)
{
    using CancellationTokenSource cts = new();

    // タイマーをバックグランドで開始
    Task periodictask = PeriodicTimerSampleAsync(TimeSpan.FromMilliseconds(100), cts.Token);

    Console.ReadLine(); // 何か入力するまで待ち

    cts.Cancel(); // 抜けたらキャンセルしてから

    await periodictask; // 終了まち
}

100msの周期ですが、必ず100ms周期で実行されるのではなく 90~110msの範囲で待機時間は変動します。

また 100ms 周期で処理が 120ms など待機時間を超過した場合次の待機時間がゼロで連続して次の処理が実行されるので実行時間が超えないように調整する or あまりに短い連続呼び出しはスキップするなど追加で実装が必要です。

簡単ですが今回は以上です