none
Delegates versus anonymous methods performance peculiarity. RRS feed

  • Question

  • Hi There

    It's puzzling me while the following scenarios are yielding a huge performance difference:

            
    
    
            Action action;
    
    
    private void methodA()
            {
                action= new Action(calculate);
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    method1();
                }
                sw.Stop();
                MessageBox.Show(sw.ElapsedMilliseconds.ToString());
            }
    
            private void method1()
            {
                action.BeginInvoke(null, null);
            }
    
            private void calculate()
            {
                int z = 5;
                z++;
            }

    Versus:

            private void methodB()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    method2();
                }
                sw.Stop();
                MessageBox.Show(sw.ElapsedMilliseconds.ToString());
            }
    
    
            private static void method2()
            {
                Action method = new Action(
                () =>
                {
                    int z = 5;
                    z++;
                }
                );
                method.BeginInvoke(null, null);
            }

    versus:

            private void methodC()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    int z = 5;
                    z++;
                }
                sw.Stop();
                MessageBox.Show(sw.ElapsedMilliseconds.ToString());
            }

    Method A is showing 37518

    Method B is showing 18805

    Method C is showing  2

    Obviously it's obvious why C is much faster but the difference between A and B is not that clear to me. The difference is pretty consistent no matter how many times I try B seems to be running at least twice as fast. Although theortically A is cleaner since it's not re-creating an action delegate for each call. I understand the compiler might be doing this anyway but there would be a null check that should still make B slightly slwoer than A.

    Anyone can shed some light on this?

    Tuesday, February 21, 2012 4:31 PM

Answers

  • Dear Reed

    Many thanks for your reply. However, My question is specifically of why begininvoke is faster with anonymous/lambda calls than in explicit delegates. I have tried invoke and got similiar results to you which is understood.

    What I can't understand is why ,when using begininvoke,  B is always at least twice as fast as A regardless of which one i try first and outside vs i'm gettting same resutls. it's pretty consistent and looking into the IL code didn't uncover anything special. BeginInvoke is obviously a lot more involved than Invoke but why is it always faster to use begininvoke on an anonymous method than using it on an explicit delegate?

    The main difference in speed between method A and method B is actually this:

    private void calculate()
    {

    Since you made this an instance method, the delegate has to hold a reference to the actual object, and the BeginInvoke call gets some extra overhead involved with passing the object around and using callvirt vs. call, etc.

    The lambda expression, however, gets resolved to a static method since it's not closing over any variables.  Since it's static, it runs quite a bit faster.

    If you make calculate static, in methodA, then it will actually be (slightly) faster than methodB - on my system, it ends up 7112 vs 7435 ms.

    Try taking your original code, and changing nothing except making it:

    private static void calculate()
    {

    You'll see timings more like you were expecting.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, February 22, 2012 12:07 AM
    Moderator

All replies

  • Your timings are getting horribly skewed because you're using BeginInvoke, not Invoke.  Delegate.BeginInvoke  uses the thread pool, and invokes a lot of extra scheduling, which in turn causes things to be a bit crazy.  

    Try the following code - it will give you timings more along your expectations.  As you'd expect, B is a bit slower due to the overhead of the GC having to clean up the delegate, but otherwise, very similar in speed.  I switched to reporting ticks instead of milliseconds (since it was showing as 0-3ms, not enough to see a real difference).  Also, make sure to run outside of Visual Studio, with a release build, to see the full effect.

    With this, I get:

    MethodA: 14055
    MethodB: 18605
    MethodC: 1875
    MethodA: 12216
    MethodB: 16905
    MethodC: 1875
    MethodA: 12282
    MethodB: 19684
    MethodC: 1875

    using System;
    using System.Reflection;
    namespace Test
    {
        using System.Diagnostics;
    
        public class Program
        {
            private static void Main()
            {
                Program program = new Program();
    
                for (int i = 0; i < 3; ++i)
                {
                    program.methodA();
                    program.methodB();
                    program.methodC();
                }
    
                Console.ReadKey();
            }
    
            Action action;
    
            private void methodA()
            {
                action = new Action(calculate);
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    method1();
                }
                sw.Stop();
                Console.WriteLine("MethodA: {0}", sw.ElapsedTicks);
            }
    
            private void method1()
            {
                action.Invoke();
            }
    
            private void calculate()
            {
                int z = 5;
                z++;
            }
    
            private void methodB()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    method2();
                }
                sw.Stop();
                Console.WriteLine("MethodB: {0}", sw.ElapsedTicks);
            }
    
    
            private static void method2()
            {
                Action method = new Action(
                () =>
                {
                    int z = 5;
                    z++;
                });
    
                method.Invoke();
            }
    
            private void methodC()
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    int z = 5;
                    z++;
                }
                sw.Stop();
                Console.WriteLine("MethodC: {0}", sw.ElapsedTicks);
            }
        }
    }

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Tuesday, February 21, 2012 6:39 PM
    Moderator
  • Dear Reed

    Many thanks for your reply. However, My question is specifically of why begininvoke is faster with anonymous/lambda calls than in explicit delegates. I have tried invoke and got similiar results to you which is understood.

    What I can't understand is why ,when using begininvoke,  B is always at least twice as fast as A regardless of which one i try first and outside vs i'm gettting same resutls. it's pretty consistent and looking into the IL code didn't uncover anything special. BeginInvoke is obviously a lot more involved than Invoke but why is it always faster to use begininvoke on an anonymous method than using it on an explicit delegate?

    Tuesday, February 21, 2012 10:28 PM
  • Dear Reed

    Many thanks for your reply. However, My question is specifically of why begininvoke is faster with anonymous/lambda calls than in explicit delegates. I have tried invoke and got similiar results to you which is understood.

    What I can't understand is why ,when using begininvoke,  B is always at least twice as fast as A regardless of which one i try first and outside vs i'm gettting same resutls. it's pretty consistent and looking into the IL code didn't uncover anything special. BeginInvoke is obviously a lot more involved than Invoke but why is it always faster to use begininvoke on an anonymous method than using it on an explicit delegate?

    The main difference in speed between method A and method B is actually this:

    private void calculate()
    {

    Since you made this an instance method, the delegate has to hold a reference to the actual object, and the BeginInvoke call gets some extra overhead involved with passing the object around and using callvirt vs. call, etc.

    The lambda expression, however, gets resolved to a static method since it's not closing over any variables.  Since it's static, it runs quite a bit faster.

    If you make calculate static, in methodA, then it will actually be (slightly) faster than methodB - on my system, it ends up 7112 vs 7435 ms.

    Try taking your original code, and changing nothing except making it:

    private static void calculate()
    {

    You'll see timings more like you were expecting.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, February 22, 2012 12:07 AM
    Moderator