Avoid Invoke(), prefer BeginInvoke()
This is another post in a series that deals with asynchronous behaviour (see also here and here).
The difference between Control.Invoke() and Control.BeginInvoke() is:
- BeginInvoke() will schedule the asynchronous action on the GUI thread. When the asynchronous action is scheduled, your code continues. Some time later (you don't know exactly when) your asynchronous action will be executed.
- Invoke() will execute your asynchronous action (on the GUI thread) and wait until your action has completed.
A logical conclusion is that a delegate you pass to Invoke() can have out-parameters or a return-value, while a delegate you pass to BeginInvoke cannot (you have to use EndInvoke to retrieve the results).
My advice is: always use BeginInvoke() if you can. Reasons:
- Because Invoke() causes one thread to wait for another thread, it is likely to cause deadlocks. Imagine that your application has a dedicated worker thread that uses Invoke() to execute some work on the GUI thread. Now image that during this work, your GUI code needs to execute something on the worker-thread. It will be blocked forever because your worker-thread is already busy waiting for your GUI-thread.
In this simple example it might be easy to spot the problem. In a big application developed by many people it will not always be this easy. Therefore it is better to find a pattern that avoids blocking altogether.
Note that in this example you might think that a threadpool solves your problem, because then you have multiple workerthreads. However the problem will still occur under high load, this is called threadpool starvation and it is a very complex problem. Because it only occurs under high load, it is a very dangerous thing that is very difficult to debug. - Invoke() will cause forced threadswitches that will decrease the scalability of your application.
First consider BeginInvoke: when it is called, a delegate is scheduled to be executed on the other thread. However your current thread will continue until the operating system decides that it's done enough work. Only then will the other thread (GUI thread) be executed, and your delegate will be run. If other delegates were also scheduled using BeginInvoke(), they will be executed as well.
Now consider Invoke: when you call it, the OS immedeately has to stop your current thread and schedule the other thread.
When more than one Invoke()-statement is done, a threadswitch will be needed every single time (whereas multiple BeginInvoke-requests can be bundled in one threadswitch).
Excessive threadswitches will seriously hurt performance when your application is under a high load.
Conclusion: avoid using Invoke().