C# EndInvoke() 是可选的,某种可选的,还是绝对不是可选的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/532722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 07:04:48  来源:igfitidea点击:

Is EndInvoke() optional, sort-of optional, or definitely not optional?

c#multithreadingdelegates

提问by endian

I've read conflicting opinions as to whether every BeginInvoke() has to be matched by an EndInvoke(). Are there any leaks or other problems associated with NOT calling EndInvoke()?

关于是否每个 BeginInvoke() 都必须与 EndInvoke() 匹配,我读到了相互矛盾的意见。是否存在与不调用 EndInvoke() 相关的任何泄漏或其他问题?

采纳答案by Marc Gravell

Delegate.EndInvoke is documented as a thou shalt call this(i.e. necessary - else leaks happen) - from msdn:

Delegate.EndInvoke 被记录为你应该调用它(即必要 - 否则会发生泄漏) - 来自msdn

Important Note

No matter which technique you use, always call EndInvoke to complete your asynchronous call.

重要的提示

无论您使用哪种技术,始终调用 EndInvoke 来完成异步调用。

Control.EndInvoke is OK to ignore for fire-and-forget methods - from msdn:

Control.EndInvoke 可以忽略即发即弃方法 - 来自msdn

You can call EndInvoke to retrieve the return value from the delegate, if neccesary, but this is not required.

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

However - if you are using Delegate.BeginInvokeand don't want the result, consider using ThreadPool.QueueUserWorkIteminstead - it'll make life a lot easier, and avoid the pain of IAsyncResultetc.

但是 - 如果您正在使用Delegate.BeginInvoke并且不想要结果,请考虑使用ThreadPool.QueueUserWorkItem- 它会让生活更轻松,并避免等的痛苦IAsyncResult

回答by Luca Martinetti

EndInvoke is not optional.

EndInvoke 不是可选的。

More info here

更多信息在这里

回答by JaredPar

And EndInvoke call is not optional call, it is a part of the contract. If you call BeginInvoke you must call EndInvoke.

而 EndInvoke 调用不是可选调用,它是合约的一部分。如果您调用 BeginInvoke,则必须调用 EndInvoke。

Classic example of why this is necessary. It's very possible that the IAsyncResult returned from BeginInvoke has allocated resources attached to it. Most commonly a WaitHandle of sorts. Because IAsyncResult does not implement IDisposable another place must be chosen to free the resources. The only place to do so is EndInvoke.

为什么这是必要的经典示例。从 BeginInvoke 返回的 IAsyncResult 很有可能已经分配了附加到它的资源。最常见的是一种WaitHandle。因为 IAsyncResult 没有实现 IDisposable,所以必须选择另一个地方来释放资源。唯一可以这样做的地方是 EndInvoke。

I briefly discuss this problem in the following blog post.

我在下面的博客文章中简要讨论了这个问题。

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

回答by Maghis

EndInvoke is not optional because it is the place where exceptions are thrown if something went wrong in the asyncronous processing.

EndInvoke 不是可选的,因为它是在异步处理中出现问题时抛出异常的地方。

Anyway there should not be any leak because if the IAsyncResult is holding some native resource it should correctly implement IDisposable and dispose such resources when the GC calls his finalizer.

无论如何不应该有任何泄漏,因为如果 IAsyncResult 持有一些本机资源,它应该正确实现 IDisposable 并在 GC 调用他的终结器时处理这些资源。

回答by Steve

Its only optional if you don't mind your program's memory growing very large. The issue is that the GC is holding onto all of the references in your thread, because you might want to call EndInvoke at some point. I would go with Marc's answer, the threadpool will make your life easier. However, you need to watch out if you spawn threads from your threads, as it is limited in the number of threads it can spin up.

如果您不介意程序的内存增长得非常大,它只是可选的。问题是 GC 保留了线程中的所有引用,因为您可能想在某个时候调用 EndInvoke。我会同意 Marc 的回答,线程池会让你的生活更轻松。但是,您需要注意是否从您的线程中生成线程,因为它可以启动的线程数是有限的。

回答by James Alexander

It is not optional because calling BeginInvoke makes use of a WaitHandle which in turns makes use of a kernel object that maintains a count for how many references are had to it. Calling EndInvoke gracefully disposes the handle which decrements that counter on the kernel object and when that count reaches zero, the kernel object manager will destroy it.

它不是可选的,因为调用 BeginInvoke 会使用 WaitHandle,WaitHandle 又会使用内核对象,该对象维护对它有多少引用的计数。优雅地调用 EndInvoke 处理在内核对象上递减该计数器的句柄,当该计数达到零时,内核对象管理器将销毁它。

回答by Robert Oschler

Every reply on this post says that EndInvoke() is not optional. However, I found the following highly ranked comment that is the accepted answer on this SO thread:

这篇文章的每个回复都说 EndInvoke() 不是可选的。但是,我发现以下排名靠前的评论是此 SO 线程上已接受的答案:

"Note that the Windows Forms team has guaranteed that you can use Control.BeginInvoke in a 'fire and forget' manner - i.e. without ever calling EndInvoke. This is not true of async calls in general: normally every BeginXXX should have a corresponding EndXXX call, usually in the callback."

“请注意,Windows 窗体团队已保证您可以以“即发即忘”的方式使用 Control.BeginInvoke - 即永远不会调用 EndInvoke。一般异步调用并非如此:通常每个 BeginXXX 都应该有一个相应的 EndXXX 调用,通常在回调中。”

What's the difference between Invoke() and BeginInvoke()

Invoke() 和 BeginInvoke() 有什么区别