Delegate.BeginInvoke与ThreadPool.QueueWorkerUserItem的区别

6
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var replyCopy = reply;

        ThreadPool.QueueUserWorkItem(delegate
        {
            RequestQueueHandler.RequestQueue.Add((Message)correlationState, replyCopy);
        });
    }

vs

    private delegate void RequestQueueHandlerAdd(Message request, Message reply);

    private static void AsyncMethod(Message request, Message reply)
    {
        RequestQueueHandler.RequestQueue.Add(request, reply);
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        ((RequestQueueHandlerAdd)AsyncMethod).BeginInvoke((Message)correlationState, reply, null, null);
    }

这两个中应该使用哪一个?(哪个性能更好?) 为什么? 我的方法的开销是否影响决策,还是其中一种实现总是比另一种更优? 为什么?

我倾向于使用ThreadPool.QueueWorkerUserItem,但我不知道哪一个实际上更好,无论在这种情况下还是一般情况下。

更新

我读了一些关于TPL的东西..得出了以下结论:

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var replyCopy = reply;
        var enqueue = Task.Factory.StartNew(() => RequestQueueHandler.RequestQueue.Add((Message)correlationState, replyCopy));

    }

我应该如何处理这里的异常?我的意思是,如果我执行

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var replyCopy = reply;
        var enqueue = Task.Factory.StartNew(() => RequestQueueHandler.RequestQueue.Add((Message) correlationState, replyCopy));

        **try
        {
            enqueue.Wait();
        }
        catch(AggregateException e)
        {
            Handle(e);
        }**
    }

我是不是在这里错过了并行性的全部要点?

难道我不应该只处理RequestQueueHandler.RequestQueue.Add方法中可能抛出的异常吗?


1
你使用的是哪个版本的.NET?如果你使用的是.NET 4,那么你应该使用任务并行库(Task Parallel Library)。嗯,不是“应该”,而是“强烈建议”。 - Tejs
我正在使用框架4.0,你能详细说明一下吗?或者可以把它作为一个答案发布吗? - bevacqua
3个回答

3
Delegate.BeginInvoke() 方法也使用线程池,因此不要期望在性能上有任何实质性的差异。 QueueUserWorkItem() 并不直接更好,只是在大多数情况下更容易。
但请注意,这两个示例都缺少错误处理。 您简洁明了的委托需要一个 try/catch,而 BeginInvoke 场景需要一个回调。
因此,当您可以使用 Fx4 时,应该使用 TPL 来获得更高的抽象级别。

2
иҝҷзҜҮж–Үз« жҸӯзӨәдәҶBeginInvokeе’ҢQueueUserWorkItemд№Ӣй—ҙзҡ„йҮҚеӨ§еҢәеҲ«пјҢдёӨиҖ…йғҪдёҺзј–зЁӢзӣёе…ігҖӮ - Gqqnbig

2
异步委托提供了更多的功能:返回值和异常转发(您应该调用EndInvoke来访问它们)。 直接使用线程池时,您必须自己处理这些问题。
另一方面,线程池的优点是简单易用。
请查看这本优秀的在线书籍,深入探讨了这两种(及更多)方法。
作为经验法则:
  • 如果可以,请使用TPL
  • 如果不能,请直接使用线程池进行简单的“fire-and-forget”任务
  • 如果还不行,请使用异步委托

你能详细介绍一下TPL吗?可以提供一个链接吗? - bevacqua
当然。上述书籍中有一章关于并行编程:http://www.albahari.com/threading/part5.aspx,请参考维基百科:http://en.wikipedia.org/wiki/Task_Parallel_Library#Task_Parallel_Library - grzeg
QueueWorkerUserItem的优点是你无需等待答案,但必须最终跟随BeginInvoke的是EndInvoke,否则将会造成内存泄漏。 - Jaap

1

ThreadPool.QueueWorkerUserItem 是更高级和首选的方法。 但是,ThreadPool.QueueWorkerUserItem 在幕后使用了 Delegate.BeginInvoke 但是,Delegate.BeginInvoke 使用了来自 ThreadPool 的线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接