[解決済み] TPLタスクオブジェクトでDispose()を呼び出さないことは許容されると考えられますか?
質問
バックグラウンドスレッドでタスクを実行させたいと思います。私はタスクの完了を待ちたくありません。
.net 3.5では、私はこれを行いました。
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
.net 4では、TPLが推奨される方法です。私が見たことのある一般的なパターンは、推奨されています。
Task.Factory.StartNew(() => { DoSomething(); });
ただし
StartNew()
メソッドが返すのは
Task
を実装したオブジェクトを返します。
IDisposable
. これは
は、このパターンを推奨する人たちから見落とされているようです。MSDN のドキュメントでは
Task.Dispose()
メソッドに書かれています。
"タスクへの最後の参照を解放する前に、常にDisposeを呼び出します。
タスクが完了するまで dispose を呼び出すことはできないので、メインスレッドが待機して dispose を呼び出すことは、そもそもバックグラウンドスレッドで行う意味がなくなります。また、クリーンアップに使用できる完了/終了イベントもないようです。
MSDN の Task クラスのページにはこれに関するコメントがなく、書籍 "Pro C#2010..." にも同じパターンが推奨されており、タスクの破棄に関するコメントはありません。
このまま放置しておけば最終的にファイナライザがキャッチしてくれるのは分かっているのですが、このようなfire & forgetタスクをたくさんやっていてファイナライザのスレッドが圧迫されたときに、これは返ってくるのでしょうか?
そこで質問です。
-
を呼び出さないことは許容されるのでしょうか?
Dispose()
の上でTask
クラスで使用できますか?そして、もしそうなら、その理由とリスク/結果はあるのでしょうか? - このことについて説明しているドキュメントはありますか?
-
それとも
Task
オブジェクトを破棄する適切な方法があるのでしょうか? - あるいは、TPL で fire & forget タスクを行う別の方法がありますか。
どのように解決するのですか?
この件に関する議論があります について、MSDN フォーラムで .
Microsoft pfx チームのメンバーである Stephen Toub はこのように言っています。
Task.Dispose が存在するのは、Task がイベント ハンドルをラップしている可能性があるためです。 タスクが完了するのを待つときに使用される 待ちのスレッドが実際にブロックしなければならない場合 スレッドが実際にブロックする必要があるためです。 待機中のスレッドが実際にブロックしなければならない場合(スピンする、あるいは潜在的に 待機しているスレッドが実際にブロックしなければならない場合(回転したり、待機しているタスクを実行する可能性があるのとは対照的です)。 もし、あなたがやっていることが を使用している場合、そのイベントハンドルは が割り当てられることはありません。
...
ということで、ファイナライズに頼るほうがよさそうです。
更新情報(2012年10月)
Stephen Toubは、以下のタイトルのブログを投稿しています。
タスクの破棄は必要ですか?
というタイトルのブログを投稿し、いくつかの詳細と .Net 4.5 での改善点を説明しています。
要約すると、タスクの破棄は必要ありません。
Task
オブジェクトは99%の確率で廃棄する必要はありません。
オブジェクトを破棄する主な理由は2つあります。タイムリーで決定論的な方法で管理されていないリソースを解放するためと、オブジェクトのファイナライザーを実行するコストを回避するためです。これらはどちらも
Task
にはほとんど当てはまりません。
-
.Net 4.5時点では、唯一
Task
が内部待機ハンドル(の中で唯一管理されていないリソース)を 割り当てるときだけです。Task
のIAsyncResult.AsyncWaitHandle
であり -
は
Task
オブジェクト自体はファイナライザを持ちません。ハンドルはそれ自体がファイナライザを持つオブジェクトにラップされているので、それが割り当てられない限り、実行すべきファイナライザはありません。
関連
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み] 'SubSonic.Schema .DatabaseColumn' 型のオブジェクトをシリアライズする際に、循環参照が検出されました。
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み] C#でawaitを使わずに非同期メソッドを安全に呼び出す方法
-
[解決済み】HttpClientとHttpClientHandlerはリクエストの間にディスポされなければならないのでしょうか?
-
[解決済み】スレッドをタイムアウトさせる方法
-
[解決済み] CancellationTokenSourceを破棄するタイミングは?
-
[解決済み】複数の非同期タスクを実行し、すべてのタスクが完了するのを待つ
-
[解決済み] ガベージコレクタはIDisposable.Disposeを呼んでくれるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】SmtpException: トランスポート接続からデータを読み取れません:net_io_connectionclosed
-
[解決済み] [Solved] アセンブリ System.Web.Extensions dll はどこにありますか?
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み】Unity 「関連するスクリプトを読み込むことができません」「Win32Exception: システムは指定されたファイルを見つけることができません"
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】2年前のMSDateを把握する【クローズド
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み] すべてのサーバーサイドのコードでConfigureAwaitを呼び出すためのベストプラクティス