1. ホーム
  2. c#

[解決済み】Task<T>の完了をタイムアウトで非同期に待つ

2022-03-23 11:28:13

質問

を待ちたいのですが。 タスク<T> を、いくつかの特別なルールで完了させます。 Xミリ秒経っても完了しない場合、ユーザーにメッセージを表示したい。 また、Yミリ秒経過しても完了しない場合は、自動的に キャンセル依頼 .

を使うことができますね。 タスク.ContinueWith を使えばタスクの完了を非同期に待つことができます (つまり、タスクが完了したときに実行されるアクションをスケジュールする) が、これではタイムアウトを指定することができないのです。 しかし、これではタイムアウトを指定できません。 タスク.ウェイト を使えば、タスクの完了をタイムアウト付きで同期的に待つことができますが、これでは私のスレッドがブロックされてしまいます。 どうすればタイムアウトを伴うタスクの完了を非同期で待つことができるでしょうか?

解決するには?

こんなのはどうでしょう。

int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
    // task completed within timeout
} else { 
    // timeout logic
}

そして、こちらが この種のものについての詳細は、ブログ記事 "Crafting a Task.TimeoutAfter Method" (from MS Parallel Library team) を参照してください。 .

追加 : 私の回答に対するコメントで要望がありましたので、キャンセル処理を含む拡大した解決策を紹介します。タスクとタイマーにキャンセルを渡すということは、コードの中でキャンセルを経験する方法が複数あるということで、それらすべてを適切に処理するためのテストと確信が必要です。様々な組み合わせを偶然に任せたり、実行時にコンピュータが正しい動作をすることを願ったりしないようにしましょう。

int timeout = 1000;
var task = SomeOperationAsync(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
    // Task completed within timeout.
    // Consider that the task may have faulted or been canceled.
    // We re-await the task so that any exceptions/cancellation is rethrown.
    await task;

}
else
{
    // timeout/cancellation logic
}