views:

703

answers:

2

C# 3.0 in a nutshell says asynchronous methods and asynchronous delegates looks similar but the behavior is very different.

Here is what the book says about both.

Asynchronous methods

  1. Rarely or never blocks any thread.
  2. Begin method may not immediately return to the caller.
  3. An agreed protocol with no C# language support.

Asynchronous delegates

  1. May block for any length of time
  2. BeginInvoke return immediately to the caller.
  3. Built-in compiler support.

The book also says, The purpose of asynchronous methods is to allow many tasks to run on few threads; the purpose of asynchronous delegates is to execute a task in parallel with the caller.

When I looked into the BeginRead() method in System.IO.Stream class through reflector, it is using a delegate and calling BeginInvoke on that. So an asynchronous method is using an asynchronous delegate internally.

  1. In such case, how can one say their behaviors are different? Since it uses delegates internally, how a comparison like the above is possible?
  2. Do you think working with a delegate's BeginXXX method is the way to execute a function in parallel to the caller?
  3. What is the proper way to implement asynchronous methods by maintaining all the advantages like making good use of CPU?

Any thoughts?

+3  A: 
  1. The implementation can be different; for example, an async IO call may choose to make use of completion ports to minimise the cost to the system while not doing anything.
  2. It is certainly a way; you could also use BackgroundWorker, ThreadPool.QueueUserWorkItem, or Parallel.For (etc) in .NET 4.0
  3. Varies per implementation

I think what the book is trying to highlight is that delegates always include this pattern:

  • a synchronous call (Invoke) that can block
  • an async call (BeginInvoke) that shouldn't really block unless the thread-pool is saturated

but it isn't the only pattern. Also; more recently (for example, the async IO methods in Silverlight, or in WebClient): rather than an IAsyncResult, an event is used to signal completion.

Marc Gravell
Thanks for the reply. Can you point me to a framework class which has a different asynchronous method implementation?
Appu
Perhaps something like `SqlCommand.BeginExecute*` or `HttpWebRequest.BeginGetResponse`
Marc Gravell
Great. SqlCommand has some interesting implementations.
Appu
+3  A: 

At the core, there are two main behaviors you may see when you call BeginFoo() with a callback.

  1. Work is started on a background thread, and that thread will be used the entire time up until the work is completed and the callback is invoked (e.g. because the work is synchronous).
  2. Though some work happens on a background thread, the thread need not be in use the entire time (e.g. because the work involves System IO which can schedule callbacks on e.g. the IOCompletionPort).

When you use a delegate, behavior #1 above happens.

Some APIs (that have underlying support for non-blocking IO calls) support behavior #2.

In the specific case of 'Stream', I am not sure, but my guess is it is an abstract base class and so this is merely the default behavior for a subclass that implements only a synchronous version of Read. A 'good' subclass would override BeginRead/EndRead to have a non-blocking implementation.

The advantage of #2, as you said, is that you can have e.g. 100 pending IO calls without consuming 100 threads (threads are expensive).

Brian
+1. Thanks for the reply. This makes more sense.
Appu