すべてのBeginInvoke()をEndInvoke()と一致させる必要があるかどうかについて、相反する意見を読みました。 EndInvoke()を呼び出さないことに関連するリークやその他の問題はありますか?
Delegate.EndInvokeは、これを呼び出す必要がある(つまり、必要な-そうでない場合はリークが発生する)-from msdn :として文書化されています。
重要な注意
どの手法を使用する場合でも、常にEndInvokeを呼び出して非同期呼び出しを完了してください。
Control.EndInvokeは、ファイアアンドフォーゲットメソッドでは無視しても問題ありません-from msdn :
必要に応じて、EndInvokeを呼び出してデリゲートから戻り値を取得できますが、これは必須ではありません。
ただし、Delegate.BeginInvoke
を使用していて結果が必要ない場合は、代わりにThreadPool.QueueUserWorkItem
を使用することを検討してください。これにより、作業が大幅に楽になり、IAsyncResult
などの苦痛を回避できます。
EndInvokeはオプションではありません。
詳細 ここ
また、EndInvoke呼び出しはオプションの呼び出しではなく、コントラクトの一部です。 BeginInvokeを呼び出す場合は、EndInvokeを呼び出す必要があります。
これが必要な理由の典型的な例。 BeginInvokeから返されたIAsyncResultに、それに接続されたリソースが割り当てられている可能性があります。最も一般的には、ある種のWaitHandleです。 IAsyncResultはIDisposableを実装していないため、リソースを解放するために別の場所を選択する必要があります。そのための唯一の場所はEndInvokeです。
この問題については、次のブログ投稿で簡単に説明します。
http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx
EndInvokeは、非同期処理で問題が発生した場合に例外がスローされる場所であるため、オプションではありません。
とにかく、IAsyncResultがネイティブリソースを保持している場合、IDisposableを正しく実装し、GCがファイナライザーを呼び出すときにそのようなリソースを破棄する必要があるため、リークは発生しないはずです。
BeginInvokeを呼び出すと、WaitHandleが使用され、WaitHandleは、参照が必要な数のカウントを維持するカーネルオブジェクトを使用するため、オプションではありません。 EndInvokeを呼び出すと、カーネルオブジェクトのカウンターをデクリメントするハンドルが適切に破棄され、そのカウントがゼロに達すると、カーネルオブジェクトマネージャーがハンドルを破棄します。
この投稿へのすべての返信は、EndInvoke()はオプションではないと述べています。しかし、私はこのSOスレッドで受け入れられた答えである次の高ランクのコメントを見つけました:
「Windowsフォームチームは、Control.BeginInvokeを「ファイアアンドフォーゲット」方式で、つまりEndInvokeを呼び出さずに使用できることを保証していることに注意してください。これは、一般的な非同期呼び出しには当てはまりません。通常、すべてのBeginXXXには対応するEndXXX呼び出しが必要です。 、通常はコールバックで。」
プログラムのメモリが非常に大きくなることを気にしない場合は、これが唯一のオプションです。問題は、ある時点でEndInvokeを呼び出したい場合があるため、GCがスレッド内のすべての参照を保持していることです。私はマークの答えに行きます、スレッドプールはあなたの人生を楽にします。ただし、スピンアップできるスレッドの数には制限があるため、スレッドからスレッドを生成するかどうかに注意する必要があります。