バックグラウンドスレッドでタスクを実行したいのですが。タスクの完了を待ちたくありません。
.net 3.5では、私はこれをしただろう:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
.NET 4では、TPLが推奨される方法です。私がお勧めするのを見たことがある一般的なパターンは、
Task.Factory.StartNew(() => { DoSomething(); });
しかしStartNew()
メソッドはTask
実装するオブジェクトIDisposable
。この
このパターンを推薦する人たちは見落とされているようです。上のMSDNドキュメントTask.Dispose()
方法は言う:
「タスクへの最後の参照を解放する前に、必ずDisposeを呼び出してください。」
タスクが完了するまでdisposeを呼び出すことはできません。そのため、メインスレッドを待機させてdisposeを呼び出しても、バックグラウンドスレッドを最初に実行することの意味がなくなります。クリーンアップに使用される可能性のある完了/終了イベントもありません。
TaskクラスのMSDNページはこれについてコメントしていません、そして、本 "Pro C#2010 ..."は同じパターンを推薦し、タスク処分についてコメントしません。
ファイナライザが最後にそれをキャッチすることを私がちょうどそれを去るかどうか私は知っている、しかしこれは戻って来てそして私がたくさんの火をやっているとき私を噛むつもりである。このようなタスクを忘れると、ファイナライザスレッドは圧倒されますか?
だから私の質問は次のとおりです。
Dispose()
にTask
この場合のクラスは?そしてもしそうなら、なぜそしてリスク/結果はありますか?Task
私が逃したオブジェクト?
これについての議論がありますMSDNフォーラムで。
Microsoft pfxチームの一員であるStephen Toub氏は、次のように述べています。
Task.DisposeはTaskのために存在します イベントハンドルをラップする可能性がある タスクを待つときに使用されます イベントが発生した場合は完了 スレッドは実際にブロックしなければなりません。 紡績に反対したり潜在的に 待っているタスクを実行する あなたがしているのが使っているだけの場合 継続、そのイベントハンドルは 割り当てられない
...
物事の面倒をみるためにはファイナライズに頼るほうがよいでしょう。
アップデート(2012年10月)
Stephen Toubがというタイトルのブログを投稿しました。タスクを破棄する必要がありますか?これはより詳細な情報を提供し、.Net 4.5の改良点を説明しています。
要約すると:あなたは処分する必要はありませんTask
99%の割合のオブジェクト。
オブジェクトを破棄する主な理由は2つあります。管理されていないリソースをタイムリーで確定的な方法で解放することと、オブジェクトのファイナライザを実行するコストを回避することです。どちらも該当しませんTask
ほとんどの時間:
Task
内部待機ハンドル(システムで唯一の管理されていないリソース)を割り当てます。Task
object)は、明示的にIAsyncResult.AsyncWaitHandle
のTask
、そしてTask
オブジェクト自体にはファイナライザはありません。ハンドル自体はファイナライザを使用してオブジェクトにラップされるため、割り当てられていない限り、実行するファイナライザはありません。EndInvoke
WinFormsで使用する場合BeginInvoke
UIスレッドでコードを実行します。 (2)Stephen Toubは、PFXの効果的な使用方法に関する定期的な講演者として非常によく知られています(例:channel9.msdn.comつまり、誰かが良いガイダンスを与えることができれば、彼はそれをしています。彼の2番目の段落に注意してください:ファイナライザに物事を任せることが時々あります。 - Richard
これは、Threadクラスと同じ種類の問題です。 5つのオペレーティングシステムハンドルを消費しますが、IDisposableを実装しません。元のデザイナーの良い決断は、もちろんDispose()メソッドを呼び出すための合理的な方法はほとんどありません。最初にJoin()を呼び出す必要があります。
Taskクラスはこれに1つのハンドル、内部手動リセットイベントを追加します。これは最も安価なオペレーティングシステムリソースです。もちろん、そのDispose()メソッドは、スレッドが消費する5つのハンドルではなく、その1つのイベントハンドルしか解放できません。うん、気にしないで。
タスクのIsFaultedプロパティに興味があるはずです。それはかなり醜いトピックです、あなたはこれについてもっと読むことができますMSDNライブラリの記事。これを適切に処理したら、タスクを処理するためのコード内にも適切な場所があるはずです。
Thread
ほとんどの場合、ThreadPoolを使用します。 - svick
誰かがこの記事に示されている手法を重視するのを見たいのですが。C#での型保証された忘れ去りの非同期デリゲート呼び出し
単純な拡張メソッドは、タスクと対話するという些細なケースをすべて処理し、それをdisposeと呼ぶことができるように見えます。
public static void FireAndForget<T>(this Action<T> act,T arg1)
{
var tsk = Task.Factory.StartNew( ()=> act(arg1),
TaskCreationOptions.LongRunning);
tsk.ContinueWith(cnt => cnt.Dispose());
}
Task
によって返されたインスタンスContinueWith
しかし、スティーブントゥーブからの引用が受け入れられた答えであることを参照してください:何もタスクのブロッキング待機を実行しない場合は処分するものがありません。 - RichardTask disper = null; disper = tsk.ContinueWith(cnt => { cnt.Dispose(); disper.Dispose(); });
- Gideon Engelberth