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

时间:2009-02-10 15:27:30

标签: c# multithreading delegates

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

6 个答案:

答案 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是“一见不醒”。这有利有弊。好处是你可以忘记它。缺点是除非您在任务完成时添加自己的同步/通知机制,否则无法知道。