FeedBeast™ Online

The future is only a click away.
in

The Horse's Mouth

Performance tip/trick for Control.Invoke()

If you're a windows developer and have done any dabbling in multithreading, chances are you've come across the "golden rule" that
controls must always be accessed on the thread from which they were created. One of the easiest ways to ensure this is to use the Invoke() method built into every control, passing it a delegate to a method you want executed on the proper thread.

Well, Control.Invoke can be awfully inefficient due to its use of DynamicInvoke (which is needed because it has no static understanding of the signature of the delegate you are passing into it, i.e. its parameters/return type). However, as I just discovered, the .NET makers added a little trick that you can use to boost performance of a Control.Invoke significantly.

The trick is that while Control.Invoke accepts a simple Delegate, which could be anything, it does special checks to see if is an instance of one of two specially-recognized delegate types. If so, Control.Invoke invokes that delegate statically, saving you much overhead.

The two "special" delegates are MethodInvoker ( void () ) and EventHandler ( void ( object, EventArgs ) ). Using either of these special delegate types will result in a major speed boost, even compared to an identically-defined delegate type.

Before we get to the numbers, here is how I tested it:

        public delegate void NonStandardDelegate( object sender, EventArgs e );
        const int numRuns = 40;

        public static void ControlInvokeTest() {
            List<double> times = new List<double>( numRuns );

            for ( int k = 0; k < numRuns; k++ ) {
                Form form = new Form();
                IntPtr handle = form.Handle;

                DateTime p1 = DateTime.Now;
                for ( int i = 0; i < 100000; i++ ) {
                    form.Invoke( new EventHandler( delegate( object sender, EventArgs e ) {
                        int j = 10;
                        j++;
                    } ), null, null );
                }
                //MessageBox.Show( ( DateTime.Now - p1 ).ToString() );
                times.Add( ( DateTime.Now - p1 ).TotalMilliseconds );
                Console.Beep( 1000, 30 );
            }

            double avg = 0;
            StringBuilder results = new StringBuilder();
            foreach ( double time in times ) {
                avg += time;
                results.AppendLine( TimeSpan.FromMilliseconds( time ).ToString() );
            }
            avg /= numRuns;
            results.AppendLine( "\nAverage: " + TimeSpan.FromMilliseconds( avg ).ToString() );

            MessageBox.Show( results.ToString() );
        }


I performed the tests in three ways. What you see above, as well as EventHandler replaced with (the identically-defined) NonStandardDelegate, and then also with MethodInvoker, which required that I get rid of the parameters.

And now for the numbers. EventHandler and MethodInvoker were comparatively identical, but not so with the dynamically-invoked NonStandardDelegate:

EventHandler

0.386 s
0.390 s
0.400 s
0.369 s

MethodInvoker

0.397 s
0.376 s
0.383 s

NonStandardDelegate

2.17 s
2.09 s
2.15 s
2.05 s

So, as you can see, simply using one of the "recognized" delegate types when calling Control.Invoke can increase invocation speed by five and a half times! That's nothing to sneeze at, especially if your application makes heavy use of concurrency and Control.Invoke to update the UI on a regular basis.

Happy programming!
 

Comments

No Comments

Leave a Comment

(required)  
(optional)
(required)  
Add

About Logan1337

I'm Logan, the creator of FeedBeast! I'm a 26-year old independent software developer living in Kingston, Ontario, trying to make a living. If you're interested in true software development and new directions in operating systems, platforms, and user interfaces, contact me!

Theme design is Mira 2007 by Chris Lotter.

Copyright © The Little Software Company.

Powered by Community Server (Non-Commercial Edition), by Telligent Systems