QueueUserWorkItem()和BeginInvoke()之间的区别是什么,用于执行不需要返回类型的异步活动

继我的BeginInvoke()/ EndInvoke()问题后,在Delegate.BeginInvoke()和使用QueueUserWorkItem()异步调用委托之间的性能/其他任何方面是否存在重大差异?

http://blogs.msdn.com/cbrumme/archive/2003/07/14/51495.aspx

说:

“一个令人惊讶的事实是,这也是为什么Delegate.BeginInvoke / EndInvoke与ThreadPool.QueueUserWorkItem(或UnsafeQueueUserWorkItem,如果您了解安全隐患并希望真正有效)等等技术相比如此之慢..BeginInvoke / EndInvoke的代码路径很快变成了一般远程通道的通用消息处理代码。“

我可以想到的QueueUserWorkItem主要是您必须使用WaitCallback委托类型,如果您已经有SomeRandomDelegate实例和一些args,这看起来很棘手。 好消息是你可以用一个闭包解决这个问题:

 ThreadPool.QueueUserWorkItem( delegate { someDelegate(arg1, arg2); } ); 

此模式还可确保您在编译时获得正确的强类型(与将object状态arg传递给QueueUserWorkItem并将其转换为目标方法不同)。 直接调用方法时也可以使用此模式:

 ThreadPool.QueueUserWorkItem( delegate { SomeMethod(arg1, arg2); } ); 

显然,如果没有EndInvoke等效项,除非在方法结束时调用方法/引发事件/等等,否则也无法获得返回值…在相关注释中,您需要注意exception处理 。

EndInvoke()有一个有用但很少提及的行为 – 它重新抛出委托在原始线程的上下文中生成的所有未处理的exception,因此您可以将exception处理逻辑移动到主代码中。

此外,如果您的委托有out / ref参数,它们将被添加到EndInvoke()签名中,允许您在方法执行完毕时获取它们。

如果调用ThreadPool.QueueUserWorkItem,则工作项中引发的exception将在后台线程上未处理(除非您明确捕获它们)。 在.Net 2及更高版本中,这将终止您的AppDomain。

如果调用delegate.BeginInvoke(),则在调用EndInvoke()时会将exception排队以重新抛出。 如果你从不调用EndInvoke(),则exception基本上是’泄露’的内存(就像异步操作未释放的任何其他状态一样)。

应该没有什么大的区别,我也认为为委托生成的BeginInvoke / EndInvoke使用线程池来执行。

应该没有任何性能差异,因为Delegate.BeginInvoke和ThreadPool.QueueUserWorkItem都将在线程池线程上执行。

最大的区别是,如果你调用BeginInvoke,你必须在某个时候调用EndInvoke。 相比之下,ThreadPool.QueueUserWorkItem是“一见不醒”。 这有利有弊。 好处是你可以忘记它。 缺点是除非您在任务完成时添加自己的同步/通知机制,否则无法知道。