Saturday, September 11, 2010

Execute a synchronous method asynchronously

Delegates are abstraction of one or more functions. They can be used as general function pointers, callbacks, events and threads. One of the areas where delegates can be useful is when you need to call a synchronous method asynchronously to boost the performance. In order to do so, you will need to define a delegate with the same signature as that of the method you want to execute. By defining that delegate, you will have access to two additional method called BeginInvoke and EndInvoke which can be used in asynchronous programming. For example, say we have a method that takes in two parameters and calculates their product. In real life, the execution of such a method wouldn’t take so long. Thus, to simulate a situation where you execute a long-running method, I called Sleep method of Thread class which makes the current thread suspend for a specified amount of time. Here is the code:

public int CalculateProduct(int number1, int number2)
{
      Thread.Sleep(10000);
      return number1 * number2;
}

This method will roughly take 10 seconds to finish. So if you execute it synchronously, the application will stop responding until the job is done. But if you execute it using a delegate’s BeginInvoke method, you could still do some more tasks in the meantime. The delegate could be something like this:

public delegate int CalculateDelegate(int number1, int number2);

I suppose you want to use this approach in a Windows Forms application. On the form, there is a button control and a label control. You run the method asynchronouly and set the value of the label control to the result of the method execution. you can add the code below to the click event handler of the button control.

int val1= 5;
int val2 = 3;
int result;
CalculateDelegate myDel = new CalculateDelegate(CalculateProduct);
IAsyncResult res = myDel.BeginInvoke(val1, val2, null, null);

//You can do some more things here

result = myDel.EndInvoke(res);

When you run BeginInvoke, a new thread is created and the job is handed over to it. This method has the same paramters of the method you assigned to the delegate plus two additional parameters. The first one is a AsyncCallback delegate which is a reference to a method you would want to be executed whenever the asynchronous execution is completed. The second parameter is a custom object that is used to pass data to the callback method. If you run BeginInvoke, you will notice that execution is not blocked upon running it. It returns immediately. The method returns an IAsyncResult which is used to check the completion of the task. In fact, there are several ways to check if the task has completed or not:

• Using EndInvoke method
• Polling
• Using AsyncWaitHandle object
• Using callback method

You can use EndInvoke method to block execution until the asynchronous method completes. Right after you run this method, the execution halts and waits for the asynchronous method to return. So you can be sure that the code you put after EndInvoke runs while the asynchronous method has returned.

You can also use polling. The BeginInvoke method returns an IAsyncResult object. You can check it constantly (for example in a while loop) to see if the asynchronous execution has completed. The IAsyncResult has a property of type Boolean called IsComplete. When the asynchronous call completes, it is set to true.

IAsyncResult has a property of type WaitHandle called AsyncWaitHandle. You can use its WaitOne method to block execution until the WaitHandle object is signaled. Then you can use EndInvoke method to finish the task.

The last approach is to use a callback method. BeginInvoke method takes in a parameter of type AsyncCallback. It’s a delegate that references a method which can be called upon completion of the asynchronous method. You can also send custom data to it using the next parameter which is of type Object.

When the execution completes, you can access the result of the method execution by running EndInvoke method. Its only parameter is the return object of the BeginInvoke method which is of type IAsyncResult and its return type is the same as that of the actual method you ran asynchronously.

No comments:

Post a Comment