Delegate.EndInvoke()真的有必要吗?

时间:2011-01-03 14:01:35

标签: .net delegates begininvoke

我已经阅读了几个论坛,甚至还有一个或两个stackoverflow问题,说使用Delegate.BeginInvoke时需要Delegate.EndInvoke。我读过的很多关于使用BeginInvoke的文章都未提及使用EndInvoke。此外,我仅使用BeginInvoke部署了生产代码,并且似乎没有任何内存问题。我使用BeginInvoke的方式通常是在完成时我不关心的线程或者处理它们需要多长时间。

7 个答案:

答案 0 :(得分:43)

来自MSDN文章'Calling Synchronous Methods Asynchronously'

  

无论您使用哪种技术,   总是调用EndInvoke来完成你的   异步调用。

现在,有理论,然后有实践。您已经发现,像您之前的许多其他开发人员一样,您通常可以忽略此记录的要求。它可能是一个实现细节,EndInvoke是否真的做了一些绝对必要的事情,以防止你的应用程序崩溃,泄漏内存等。但事情是这样的:如果它是一个记录的要求,你真的应该这样做即可。这不仅仅与理论有关;它是关于在变化的情况下保护自己。

通过记录这一要求,这种异步调用机制的设计者基本上可以自由地改变BeginInvokeEndInvoke的工作方式,这样,如果有足够的理由(例如,性能提升),EndInvoke可能会突然变得更加必要。假设如果你忘记它会突然导致死锁。他们已经说过总是打电话给EndInvoke ;如果您的应用因为没有遵循此要求而停止工作,则责任就在您身上。

我不是说这一定是一种可能的情况。我的观点很简单,你不应该 - 或者至少我不会 -ask“这真的有必要吗?”用的思维方式如果我可以放弃它,那么我将,因为 记录了你应该这样做。

答案 1 :(得分:11)

如果您计划从线程中抛出异常并期望正确捕获它们,那么绝对是必要的。如果你没有调用EndInvoke,那么抛出异常的线程就会消失,你也不会知道它。

要支持EndInvoke,请提供AsyncCallback,并在该回调方法中,确保使用try / catch块将您的调用包装到EndInvoke。

如果你不关心线程中发生的事情,你可以逃避不做,我认为这是一个很好的习惯,只需要调用EndInvoke。你永远不会知道,一个初级开发人员有一天可以进入并更改你的线程中的代码,并抛出异常。然后部署更新的应用程序,服务调用开始进入。

答案 2 :(得分:9)

我听说过可能出现的内存泄漏问题。

通过关键字搜索,我找到了一个很好的讨论。

<强> 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.

这是reference

Another Reference

答案 3 :(得分:1)

MSDN告诉我,调用EndInvoke非常重要:

  

重要提示无论您使用哪种技术,请随时致电   EndInvoke来完成你的   异步调用。

答案 4 :(得分:1)

有文件证明,在使用EndInvoke执行操作时,不需要IAsyncResult(未分配任何非托管资源 - 假设您没有等待BeginInvoke) WinForms应用程序中的GUI线程。

但是,这是一般规则的特定例外:对于每个BeginOperation,必须有匹配的EndOperation。正如另一个A所述:如果GUI访问代码可以抛出,则需要EndInvoke来获取异常。

请参阅此处查看(某种)官方确认:http://blogs.msdn.com/b/cbrumme/archive/2003/05/06/51385.aspx#51395(这是来自Chris Brummie 12 May 2003 5:50pm的评论。

其他: Control.BeginInvoke的文档包含以下注释:

  

如果需要,您可以调用EndInvoke从委托中检索返回值,但这不是必需的。 EndInvoke将阻止,直到可以检索返回值。

所以它是官方的:WinForm使用异步委托在GUI线程上执行操作不 require EndInvoke(除非你需要返回值或可能的异常,否则案例考虑使用Invoke)。

答案 5 :(得分:1)

我使用BeginInvoke的方式通常是线程,我不关心它们完成时间或处理时间。

听起来你应该考虑使用Thread类而不是异步委托。

如果您关心结果检测错误(这两者都需要将结果/错误编组到原始线程),那么您可以使用异步委托,并且在这种情况下, 需要EndInvoke。更好的是,使用TaskTask<TResult>类。

如果您只想分离一些独立的操作,请使用Thread类。

答案 6 :(得分:0)

来自Windows Form documentation on Control.BeginInvoke()

  

您可以调用EndInvoke从委托中检索返回值,   如果需要,但这不是必需的。 EndInvoke将阻止直到   可以检索返回值。

这是UI线程上 Windows窗体异步调用的特殊情况,而这并不适用于一般情况,但这有助于在这种情况下的人。