web-dev-qa-db-ja.com

指定した間隔で定期的に非同期メソッドを実行します

C#Webアプリケーションからサービスにデータを公開する必要があります。ユーザーがアプリケーションを使用すると、データ自体が収集されます(一種の使用統計)。各ユーザーのリクエスト中にサービスにデータを送信したくないので、アプリでデータを収集し、ユーザーのリクエストを処理しない別のスレッドで単一のリクエストですべてのデータを送信します(つまりユーザーはリクエストがサービスによって処理されるのを待つ必要はありません)。この目的のために、JSのsetIntervalアナログのようなもの-収集されたすべてのデータをサービスにフラッシュするためにX秒ごとに関数を起動する必要があります。

Timer クラスは多少似ている( Elapsed イベント)ことがわかりました。ただし、これによりメソッドを1回だけ実行できますが、それは大きな問題ではありません。それの主な難点は、署名が必要なことです

void MethodName(object e, ElapsedEventArgs args)

私は非同期メソッドを起動したいのですが、それはウェブサービスを呼び出します(入力パラメータは重要ではありません):

async Task MethodName(object e, ElapsedEventArgs args)

誰かが説明されたタスクを解決する方法をアドバイスできますか?どんなヒントでも感謝します。

14
Eadel

同等のasyncは、Task.Delay(内部でSystem.Threading.Timerを使用する)を持つwhileループです。

public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken)
{
    while (true)
    {
        await FooAsync();
        await Task.Delay(interval, cancellationToken)
    }
}

CancellationTokenを渡すことが重要です。これにより、必要なときに(たとえば、アプリケーションをシャットダウンしたときに)その操作を停止できます。

現在、これは一般に.Netに関連していますが、ASP.Netでは、あらゆる種類の火災を実行して忘れることは危険です。これにはいくつかの解決策があります(HangFireなど)、いくつかは Stephen ClearyによるASP.NETでのFire and Forget 他の Scott HanselmanによるASP.NETでのバックグラウンドタスクの実行方法)で文書化されています

22
i3arnon

これを行う簡単な方法は、タスクと単純なループを使用することです。

public async Task StartTimer(CancellationToken cancellationToken)
{

   await Task.Run(async () =>
   {
      while (true)
      {
          DoSomething();
          await Task.Delay(10000, cancellationToken);
          if (cancellationToken.IsCancellationRequested)
              break;
      }
   });

}

スレッドを停止する場合は、トークンを中止するだけです。

cancellationToken.Cancel();
5
Guy Levin