Ziff-Davis Enterprise 
DevSource: Microsoft Developer Resource
Add OnsArchitectureLanguagesTechniquesUsing VSForums
 
Home arrow Using VS arrow Page 4 - Why Asynchronous Delegates Are Your Friend
Why Asynchronous Delegates Are Your Friend
By Jon Shemitz

Rate This Article:
Add This Article To:
Why Asynchronous Delegates Are Your Friend - ' Callback on Completion '
( Page 4 of 4 )

Callback on Completion

Every delegate's BeginInvoke method has two extra parameters after any Invoke parameters: The first is an AsyncCallback delegate and the second is an arbitrary object.

ADVERTISEMENT

If the AsyncCallback delegate is non-null, the asynchronous mechanism will Invoke it synchronously (in the same ThreadPool thread that runs the delegate; again, I talk about the system ThreadPool in the other half of this pair of articles) once the asynchronously-invoked delegate returns. An AsyncCallback delegate takes a single parameter, which is the same IAsyncResult that BeginInvoke returns and that you must pass to EndInvoke. The AsyncState property of the IAsyncResult that's passed to your AsyncCallback delegate contains the object parameter that you passed to BeginInvoke.

It took me a long time to see any sense in this callback scheme. Why two delegates? Why not just roll the second one into the first, maybe via a delegate to a method that calls the prequel and the sequel? I mean, yes, you can write a Reflection-based universal EndInvoke that will always call the right EndInvoke on the passed IAsyncResult:

public static class FireAndForget
{
  public static void EndInvoke(IAsyncResult Async)
  {
  #if DEBUG
    Delegate D = (Delegate)Async.AsyncState; 
      // raise an exception if AsyncState is not a delegate
  #else
    object D = Async.AsyncState; 
  #endif
    Type TypeofDelegate = D.GetType();
    System.Reflection.MethodInfo EndInvoke = 
      TypeofDelegate.GetMethod("EndInvoke", new Type[] { typeof(IAsyncResult) });
    EndInvoke.Invoke(D, new object[] { Async });
  }
}

You'd pass a delegate to this late-bound EndInvoke routine as the penultimate argument to BeginInvoke (the AsyncCallback delegate) and you'd pass the asynchronous delegate itself as the final argument:

FourStrings Background = new FourStrings(Quartet);
                  // FourStrings is a delegate type
Background.BeginInvoke("John", "Paul", "George", "Ringo", 
    FireAndForget.EndInvokeDelegate, Background);

But I don't think this fire and forget scenario is the real point of the callback mechanism. The real point is much more likely to be that you can break a long operation into a blocking fetcher and a post-block consumer, and both will run in the same ThreadPool thread. You certainly could use a second thread to block and resume, but that second thread is not free. The callback scheme runs both the agent that blocks and returns data and also the post-block processor in the same ThreadPool thread. ThreadPool threads are reusable, so often using a ThreadPool thread to run some code means that you can simply reuse an existing thread that's sitting idle, instead of having to create a new thread or two. Perhaps a future C# will include a language feature that generates the BeginInvoke callback from, perhaps, a using statement:

using DelegateInvoke(DelegateParams)
delegate (IAsyncResult Result)
{
  // post-block code. 
  // (using statement would automatically call EndInvoke, 
  // unless you did)
}

That would certainly make the callback feature a lot easier to use. In the meantime, I suggest you think of the callback as an advanced feature to explore when profiling reveals that you really do have too much handshaking going on. Until then, simply launching a thread by asynchronously invoking a delegate (doing as much other work as you can) and then blocking until it returns its result via EndInvoke, is not only the simplest way to pass multiple parameters to a thread, but also an efficient way to execute a method in a background thread.

New Hardware

These threading techniques are useful on single-processor machines to handle long running processes within GUI apps. On hyper-threaded and/or multi-core machines, free threading is the key to getting maximum performance. For example, many foreach loops can be easily rewritten to process each item in a new thread. It's easy to turn

foreach (T Datum in Data)
  P(Datum); // Process each Datum in the current thread

into

List AsyncResults = new List();
// Process each Datum in its own thread
foreach (T Datum in Data)
  AsyncResults.Add(P.BeginInvoke(Datum, null, null));

// Wait for all threads to finish
foreach (IAsyncResult Async in AsyncResults)
  P.EndInvoke(Async);

Instead of calling P on each Datum in turn, processing one after another, the threaded version processes each simultaneously in its own thread and then blocks until all threads complete. This slows a uni-processor machine a little, but is about twice as fast on a hyper-threaded machine, or four times as fast on a dual-core, hyper-threaded machine. (Obviously, this is schematic code; real code would make some effort to match the number of threads to the number of processors.)

Jon Shemitz is a consultant and an author. You may contact him at www.midnightbeach.com. This article will appear, in different form, in his forthcoming book, .NET 2.0 For Delphi Programmers (APress, June 2006).



 
 
>>> More Using VS Articles          >>> More By Jon Shemitz
 



DevSource video
Devsource Video Series
Manipulating Society through Technology
Jeremy Bailenson, Director of the Virtual Human Interaction Lab at Stanford University, talks about virtual reality, avatars, Moore's law, how real world behaviors influence online reality, and societal manipulation through technology!
>> Play video
>> Read article
>> See all videos
DevLife Blog

Julia explores the Robotics Studio! (It's for more than you think.)

MSDev Blog

Messages for Bill Gates!

Make it Work
.NET makes runtime type checking a breeze. See what Peter has to say about it in this week's tips!
News
Microsoft Counts on App Support for Vista
Microsoft has taken pains to demonstrate that Windows Vista will have ample application support.
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.