Zhou's profileSheva's TechSpacePhotosBlogLists Tools Help

Blog


    8/6/2007

    Delegate.BeginInvoke vs ThreadPool.QueueUserWorkItem

       Today, I come across Chris Brumme's blog on TransparentProxy, I really enjoy his blog, in particular those dedicated to the inner-working of CLR, one of the surprising sentence I read from his TransparentProxy article is that:

       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.

       I have to say I get pretty stunned when reading this, so I write a little piece of code to verify his allegation:

    using System;
    using System.Threading;
    using System.Diagnostics;

    namespace DelegatePerformance
    {
        class Program
        {
            static void Main(string[] args)
            {
                ThreadStart threadStart = new ThreadStart(() => { });
                WaitCallback waitCallback = new WaitCallback(a => { });
                Stopwatch stopWatch = new Stopwatch();

                stopWatch.Start();
                for (int i = 0; i < 10000; i++)
                {
                    threadStart.BeginInvoke(null, null);
                }
                stopWatch.Stop();
                Console.WriteLine("Delegate.BeinInvoke(): {0}",stopWatch.ElapsedTicks.ToString());

                stopWatch.Reset();
                stopWatch.Start();
                for (int i = 0; i < 10000; i++)
                {
                    System.Threading.ThreadPool.QueueUserWorkItem(waitCallback);
                }
                stopWatch.Stop();
                Console.WriteLine("ThreadPool.QueueUserWorkItem(): {0}", stopWatch.ElapsedTicks.ToString());
            }
        }
    }

       And the following output is what I get when running above programme:

      Delegate.BeinInvoke(): 591441
      ThreadPool.QueueUserWorkItem(): 91958

       From the output, there is no brainer that Delegate.BeginInvoke is way much slower than the ThreadPool.QueueUserWorkItem call.


     

    Comments (12)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.
    Zhou Yong has turned off comments on this page.
    Nov. 27
    Nov. 11
    Nov. 11
    Oct. 21
    Sept. 30
    Sept. 6
    Sept. 6
    Sept. 6
    Sept. 6
    Rob Kentwrote:
    As Tarquin says, ThreadPool.QueueUserWorkItem only adds the requests to the queue but doesn't start a thread or run the delegate, so I don't think it tells you very much about the relative costs.
    Aug. 30
    July 24

    Im not sure if this test means anything, all you are doing is creating 10 000 background threads using asynchronous calls, the most you can say is that the threadpool.queueuserworkitem creates async calls quicker than a delegate, in fact I would guess it is just creating a queue of thread requests and not the threads themselves hence its faster. A more meaningful test would be to run a few threads and make them do actual work and then use a synchronisation object to get the time expired when all threads have finished working. The comments in the blog that you mention refer to remoted objects and no doubt deleefgates need to do some extra work to connect to those objects asynchrously so they can return information on EndInvoke (Im just guessing now....)

    Nov. 15

    Trackbacks (1)

    The trackback URL for this entry is:
    http://shevaspace.spaces.live.com/blog/cns!FD9A0F1F8DD06954!580.trak
    Weblogs that reference this entry