Multithreading: understanding the BeginXXX and EndXXX methods
Now that we’ve looked at the available waiting options for the APM pattern, it’s time to start digging on its internals. This post is all about understanding the work of the BeginXXX and EndXXX methods (which isn’t much, as we’ll see).
As we’ve seen in previous posts, the BeginXXX method is responsible for kicking off the asynchronous processing. In theory, you’d expect it to create an IAsyncResult which will be responsible for:
- executing the synchronous action in a different thread (probably by using a thread from the thread pool);
- creating a kernel object that will be signaled when the synchronous action completes;
- handling eventual exceptions that might have been thrown during the execution of the task so that you can get them when you access the returned IAsyncResult returned by the EndXXX method;
As you can see, the IAsyncResult ends up doing all the work and that’s why we’ll dedicate a couple of posts to that topic.
The EndXXX method is responsible for checking the correct type of the IAsyncResult that is passed in and for getting the value of the asynchronous calculation. As you might expect, this means that you need to interact with the passed in IAsyncResult instance. You should also keep in mind that this might block if the action is not completed when you call the EndXXX method. Again, all the hard work is delegated to the IAsyncResult implementation.
If you’re curious enough and take a look at the internals of some of the existing .NET framework classes, you’ll see that some of them rely on delegates for executing the action in asynchronous way (you probably know, delegates have synchronous and asynchronous methods which are automatically generated for you). For instance, the base Stream class relies on delegates.
This is convenient but not good for the performance of your app. According to Joe Duffy, delegates rely on remoting for executing an asynchronous task and this means that you end up getting an overhead for that operation. What this means is that you’re probably better off with using the pool directly instead of creating a ”dumb” delegate for getting the asynchronous operation “for free”.
And that’s it for today. On the next post we’ll take a look at how you might create a custom IAsyncResult type. Keep tuned for more.