从我的BeginInvoke()/ EndInvoke()问题开始,在Delegate.BeginInvoke()和使用QueueUserWorkItem()以异步方式调用委托之间的性能/其他任何方面是否存在重大差异?
答案 0 :(得分:22)
QueueUserWorkItem
我能想到的主要事情是你必须使用WaitCallback
委托类型,如果你已经拥有{{1},那么看起来很棘手实例和一些args。好消息是你可以用一个闭包解决这个问题:
SomeRandomDelegate
此模式还可确保您在编译时获得正确的强类型(与将ThreadPool.QueueUserWorkItem(
delegate { someDelegate(arg1, arg2); }
);
状态arg传递给object
并将其转换为目标方法不同)。直接调用方法时也可以使用此模式:
QueueUserWorkItem
显然,如果没有等效的ThreadPool.QueueUserWorkItem(
delegate { SomeMethod(arg1, arg2); }
);
,除非你在方法结束时调用方法/引发事件/等,否则你也无法获得返回值...在相关的注释中,你需要小心exception handling。
答案 1 :(得分:17)
http://blogs.msdn.com/cbrumme/archive/2003/07/14/51495.aspx
表示:
“一个令人惊讶的事实是,这是 也为什么Delegate.BeginInvoke / 与之相比,EndInvoke非常慢 等效技术 ThreadPool.QueueUserWorkItem(或 如果您是UnsafeQueueUserWorkItem 了解安全隐患 并希望真正有效率)。该 BeginInvoke / EndInvoke的代码路径 很快变成了常见的消息 处理一般的代码 远程通路。“
答案 2 :(得分:15)
EndInvoke()有一个有用但很少提到的行为 - 它重新抛出委托在原始线程的上下文中生成的所有未处理的异常,以便您可以将异常处理逻辑移动到主代码中。
此外,如果你的委托有out / ref参数,它们将被添加到EndInvoke()签名中,允许你在方法执行完毕时获取它们。
答案 3 :(得分:4)
如果调用ThreadPool.QueueUserWorkItem,则工作项中引发的异常将在后台线程上未处理(除非您明确捕获它们)。在.Net 2及更高版本中,这将终止您的AppDomain。
如果调用delegate.BeginInvoke(),则在调用EndInvoke()时会将异常排队以重新抛出。如果你从不调用EndInvoke(),那么异常本质上就是“泄露”的内存(就像异步操作未释放的任何其他状态一样)。
答案 4 :(得分:-1)
应该没有什么大的区别,我也认为为委托生成的BeginInvoke / EndInvoke使用线程池来执行。
答案 5 :(得分:-1)
不应该有任何性能差异,因为Delegate.BeginInvoke和ThreadPool.QueueUserWorkItem都将在线程池线程上执行。
最大的区别是,如果你调用BeginInvoke,你必须在某个时候调用EndInvoke。相比之下,ThreadPool.QueueUserWorkItem是“一见不醒”。这有利有弊。好处是你可以忘记它。缺点是除非您在任务完成时添加自己的同步/通知机制,否则无法知道。