25

Delegate.BeginInvokeを使用する場合は、Delegate.EndInvokeが必要であるという、いくつかのフォーラムとスタックオーバーフローの質問を読んだことがあります。BeginInvokeの使用について私が読んだ記事の多くは、EndInvokeの使用について言及していません。また、BeginInvokeのみを使用して本番コードをデプロイしましたが、メモリの問題はないようです。私がBeginInvokeを使用した方法は、通常、スレッドがいつ終了するか、または処理にかかる時間を気にしないスレッドを使用することです。

4

7 に答える 7

45

MSDNの記事「同期メソッドの非同期呼び出し」から:

どの手法を使用する場合でも、常にEndInvokeを呼び出して非同期呼び出しを完了してください。

今、理論があり、次に実践があります。あなたは、あなたの前にいる他の多くの開発者のように、この文書化された要件を無視することでしばしば逃げることができることに気づきました。EndInvokeアプリケーションのクラッシュやメモリリークなどを防ぐために絶対に必要なことを実際に行うかどうかは、実装の詳細かもしれません。しかし、これが重要です。文書化された要件である場合は、実際に行う必要があります。これは理論だけではありません。それは変化の場合にあなた自身を守ることについてです。

この要件を文書化することにより、この非同期呼び出しメカニズムの設計者は、基本的に、方法を変更して、十分な理由(パフォーマンスの向上など)があった場合に突然必要になる可能性があるように、自由BeginInvokeに作業できるようになりました。忘れた場合、突然デッドロックが発生するとします。彼らはすでに「常に電話する」と言って自分自身をカバーしています。この要件に従わなかったためにアプリが機能しなくなった場合、責任はあなたにあります。EndInvokeEndInvokeEndInvoke

これが必ずしもありそうなシナリオだと言っているわけではありません。私の言いたいことは、「これは本当に必要なのか」と尋ねるべきではない、または少なくとも私はそうしないということです。あなたがそれをやるべきであると文書化されているので私がそれを省くことで逃げることができれば、私はそうするという考え方で。

于 2011-01-03T14:21:56.103 に答える
14

スレッドから例外をスローすることを計画していて、それらを適切にキャッチすることを期待している場合は、絶対に必要です。EndInvokeを呼び出さないと、例外をスローするスレッドが消えて、それについて何もわかりません。

EndInvokeをサポートするには、AsyncCallbackを提供し、そのコールバックメソッドで、EndInvokeへの呼び出しをtry/catchブロックでラップするようにしてください。

スレッドで何が起こっているかを気にしないのであれば、それをやらないで済ますことができますが、EndInvokeを呼び出すだけで始めるのは非常に良い習慣だと私は主張します。後輩の開発者がいつかそこに入ってスレッドのコードを変更し、例外をスローする可能性があることは決してわかりません。次に、更新されたアプリがデプロイされ、サービスコールが着信し始めます。

于 2011-01-03T14:10:52.177 に答える
9

発生する可能性のあるメモリリークの問題についてsthを聞きました。

キーワード検索で、いい議論ができました。

Does not calling EndInvoke *really* cause a memory leak ?

It can but it won't necessarily. Technically there is no such thing as a memory leak in .NET. Eventually the memory will be reclaimed by the GC. The problem is that it might be around a long time. The reason that you should call EndInvoke is because the results of the invocation (even if there is no return value) must be cached by .NET until EndInvoke is called. For example if the invoked code throws an exception then the exception is cached in the invocation data. Until you call EndInvoke it remains in memory. After you call EndInvoke the memory can be released.

これがリファレンスです

別のリファレンス

于 2011-01-03T14:12:04.047 に答える
1

MSDNによると、EndInvokeを呼び出すことが重要です。

重要な注意どの手法を使用する場合でも、常にEndInvokeを呼び出して非同期呼び出しを完了してください。

于 2011-01-03T14:11:08.117 に答える
1

WinFormsアプリケーションのGUIスレッドでアクションを実行するために使用する場合 EndInvoke、必須ではないことが文書化されています(管理されていないリソースは割り当てられません。待機しないと仮定します)。IAsyncResultBeginInvoke

ただし、これは一般的な規則の特定の例外です。すべてに一致するが必要です。ここで別のAに記載されているように、GUIアクセスコードがスローされる可能性がある場合は、例外を取得する必要があります。BeginOperationEndOperationEndInvoke

(一種の)公式確認については、こちらを参照してください:http: //blogs.msdn.com/b/cbrumme/archive/2003/05/06/51385.aspx#51395(ChrisBrummieからのコメント12 May 2003 5:50pmです。

追加:のドキュメントには、次のコメントがControl.BeginInvoke含まれています。

必要に応じて、デリゲートから戻り値を取得するために呼び出すことができますEndInvokeが、これは必須ではありません。EndInvoke戻り値を取得できるようになるまでブロックします。

したがって、公式です。WinFormで非同期デリゲートを使用してGUIスレッドでアクションを実行する必要 EndInvokeはありません(戻り値または発生する可能性のある例外が必要な場合を除き、いずれの場合もInvoke)の使用を検討してください。

于 2011-01-03T14:36:00.373 に答える
1

私がBeginInvokeを使用した方法は、通常、スレッドがいつ終了するか、または処理にかかる時間を気にしないスレッドを使用することです。

Thread非同期デリゲートの代わりにクラスの使用を検討する必要があるようです。

結果またはエラーの検出(どちらも結果/エラーを元のスレッドにマーシャリングする必要があります)に関心がある場合は、非同期デリゲートを使用できます。この場合は、必要になりますEndInvokeTaskさらに良いことに、またはTask<TResult>クラスを使用します。

独立した操作をスピンオフしたいだけの場合は、Threadクラスを使用してください。

于 2011-01-03T18:18:40.090 に答える
0

Control.BeginInvoke()のWindowsフォームドキュメントから

必要に応じて、EndInvokeを呼び出してデリゲートから戻り値を取得できますが、これは必須ではありません。EndInvokeは、戻り値を取得できるようになるまでブロックします。

これは、UIスレッドでのWindowsフォーム非同期呼び出しの特定のケースであり、これは一般的なケースには当てはまりませんが、この状況の場合に役立ちます。

于 2016-03-14T05:43:23.930 に答える