web-dev-qa-db-ja.com

TPL TaskオブジェクトでDispose()を呼び出さないことは受け入れられると考えられますか?

バックグラウンドスレッドで実行するタスクをトリガーしたい。タスクの完了を待ちたくありません。

.net 3.5では、これを行っていました。

_ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
_

.net 4では、TPLが推奨される方法です。私が推奨している一般的なパターンは次のとおりです。

_Task.Factory.StartNew(() => { DoSomething(); });
_

ただし、 StartNew() メソッドは、Taskを実装する IDisposable オブジェクトを返します。これは、このパターンを推奨する人々によって見落とされているようです。 Task.Dispose() メソッドに関するMSDNドキュメントには次のように記載されています。

「タスクへの最後の参照をリリースする前に、常にDisposeを呼び出してください。」

タスクが完了するまでdisposeを呼び出すことはできません。そのため、メインスレッドを待機させ、disposeを呼び出すと、そもそもバックグラウンドスレッドで行うことのポイントが無効になります。また、クリーンアップに使用できる完了済み/終了済みのイベントも存在しないようです。

TaskクラスのMSDNページはこれについてコメントしておらず、「Pro C#2010 ...」という本は同じパターンを推奨しており、タスクの廃棄についてはコメントしていません。

ファイナライザが最後にそれを捕まえるかどうかを知っていますが、たくさんの火をやり、このようなタスクを忘れて、ファイナライザのスレッドが圧倒されると、これが戻ってきて噛みつきますか?

だから私の質問は:

  • この場合、TaskクラスでDispose()を呼び出さないことは許容されますか?もしそうなら、なぜ、リスク/結果がありますか?
  • これについて説明するドキュメントはありますか?
  • または、私が見逃したTaskオブジェクトを廃棄する適切な方法はありますか?
  • それとも、TPLでタスクを実行してタスクを忘れる別の方法がありますか?
116
Simon P Stevens

これについての議論があります MSDNフォーラムで

Microsoft pfxチームのメンバーであるStephen Toubは次のように述べています。

Task.Disposeは、タスクが完了するのを待機しているときに使用されるイベントハンドルを潜在的にラップするために、待機スレッドが実際にブロックする必要がある場合に存在します(スピンまたは待機中のタスクの実行とは対照的に)。継続を使用している場合、そのイベントハンドルは割り当てられません
...
物事の世話をするには、ファイナライズに頼る方が良いでしょう。

更新(2012年10月)
Stephen Toubが タスクを破棄する必要がありますか? というタイトルのブログを投稿しました。このブログでは、詳細を説明し、.Net 4.5の改善点について説明しています。

要約すると、Taskオブジェクトを99%廃棄する必要はありません。

オブジェクトを破棄する主な理由は2つあります。タイムリーかつ決定的な方法でアンマネージリソースを解放することと、オブジェクトのファイナライザを実行するコストを回避することです。ほとんどの場合、これらのいずれもTaskには適用されません。

  1. .Net 4.5では、Taskが内部待機ハンドル(Taskオブジェクト内の唯一のアンマネージリソース)を割り当てるのは、TaskIAsyncResult.AsyncWaitHandleを明示的に使用するときだけです。
  2. Taskオブジェクト自体にはファイナライザーがありません。ハンドル自体はファイナライザでオブジェクトにラップされるため、割り当てられない限り、実行するファイナライザはありません。
100
Kirill Muzykov

これは、Threadクラスの場合と同じ種類の問題です。 5つのオペレーティングシステムハンドルを消費しますが、IDisposableを実装しません。元の設計者の良い決断です。もちろん、Dispose()メソッドを呼び出す合理的な方法はほとんどありません。最初にJoin()を呼び出す必要があります。

Taskクラスは、これに1つのハンドル、内部手動リセットイベントを追加します。最も安価なオペレーティングシステムリソースがあります。もちろん、そのDispose()メソッドは、スレッドが消費する5つのハンドルではなく、1つのイベントハンドルのみをリリースできます。 うん、気にしないでください

タスクのIsFaultedプロパティに興味があることに注意してください。これはかなりいトピックです。詳細については、この MSDNライブラリの記事 を参照してください。これを適切に処理すれば、タスクを破棄するための適切な場所もコードに確保する必要があります。

14
Hans Passant