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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/532791/
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:05:45  来源:igfitidea点击:

What's the difference between QueueUserWorkItem() and BeginInvoke(), for performing an asynchronous activity with no return types needed

c#multithreadingdelegates

提问by endian

Following on from my BeginInvoke()/EndInvoke() question, are there major differences in performance/anything else between Delegate.BeginInvoke() and using QueueUserWorkItem() to invoke a delegate asynchronously?

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

采纳答案by Konstantin Savelev

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

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

says:

说:

"One surprising fact is that this is also why Delegate.BeginInvoke / EndInvoke are so slow compared to equivalent techniques like ThreadPool.QueueUserWorkItem (or UnsafeQueueUserWorkItem if you understand the security implications and want to be really efficient). The codepath for BeginInvoke / EndInvoke quickly turns into the common Message processing code of the general remoting pathway."

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

回答by Marc Gravell

The main thing I can think of with QueueUserWorkItemis that you have to use the WaitCallbackdelegate type, which lookstricky if you already have a SomeRandomDelegateinstance and some args. The good news is that you can fix this with a closure:

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

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

This pattern also ensures you get proper strong typing at compile time (unlike passing an objectstate arg to QueueUserWorkItemand casting it in the target method). This pattern can also be used when calling methods directly:

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

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

Obviously, without an EndInvokeequivalent, you also can't get a return value back out unless you call a method / raise an event / etc at the end of your method... on a related note, you need to be careful with exception handling.

显然,如果没有EndInvoke等效项,您也无法获得返回值,除非您在方法结束时调用方法/引发事件/等......在相关说明中,您需要小心异常处理.

回答by Maghis

There should not be any big difference, I also think that the generated BeginInvoke/EndInvoke for a delegate uses the thread pool to execute.

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

回答by Jim Mischel

There shouldn't be any performance difference, as both Delegate.BeginInvoke and ThreadPool.QueueUserWorkItem will execute on a thread pool thread.

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

The biggest difference is that if you call BeginInvoke, you're obliged to call EndInvoke at some point. In contrast, ThreadPool.QueueUserWorkItem is "fire and forget". That has benefits and drawbacks. The benefit being that you can forget about it. The drawback being that you have no way of knowing, unless you add your own synchronization/notification mechanism, when the task has completed.

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

回答by IlyaP

The EndInvoke() has a useful but rarely mentioned behavior - it rethrows all unhandled exceptions that the delegate generated in the context of the original thread so you can move the exception processing logic into the main code.

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

Also, if your delegate has out/ref parameters, they will be added to the EndInvoke() signature allowing you to get them when method finishes execution.

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

回答by piers7

If you call ThreadPool.QueueUserWorkItem, exceptions raised in the work item will be unhandled on the background thread (unless you explicitly catch them). In .Net 2 and above this will terminate your AppDomain.

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

If you call delegate.BeginInvoke() then exceptions are queued to be re-thrown when EndInvoke() is called. If you never call EndInvoke(), then the exceptions are essentially 'leaked' memory (as is any other state not released by the async operation).

如果您调用 delegate.BeginInvoke(),那么当 EndInvoke() 被调用时,异常会排队等待重新抛出。如果您从不调用 EndInvoke(),则异常本质上是“泄漏”的内存(与异步操作未释放的任何其他状态一样)。