Asynchronous Operations

.Asynchronous Methods

"C# 5.0 introduced the async and await keywords which allows the writing of asynchronous code more easily. The compiler does the difficult work that the developer used to do, and your application retains a logical structure that resembles synchronous code. As a result, you get all the advantages of asynchronous programming with a fraction of the effort."

"Asynchrony proves especially valuable for applications that access the UI thread because all UI-related activity usually shares one thread. If any process is blocked in a synchronous application, all are blocked. Your application stops responding, and you might conclude that it has failed when instead it's just waiting."

Synchronous operations will wait for a task to finish before moving on to the next task. This waiting behavior is called blocking and causes inefficient use of a thread or a process. By contrast, an Asynchronous operation will not block, as it only initiates the task and then continues on to the next task. Asynchronous operations are well suited for tasks which can take an indeterminate amount of time to complete, such as downloading a file over a network. However asynchronous operations are more complex as they must have a way to signal the initiating process when the task is complete (call back events) and a way to abort the task if it is taking too long to complete (time out). At a lower level, asynchronous operations can involve additional complexities such as converting data into messages, handling message sequencing, and proprietary protocols for messaging. The complex nature of asynchronous code can make it more difficult to develop and debug. However when used appropriately, it can improve the responsiveness of an application. Note: Microsoft has required that all services in Silverlight be called asynchronously, and they are also strongly suggesting the same for WindowsRT.

Besides asynchronous execution, there are other ways to simultaneously perform tasks. A comparison of these modes is:

  1. Concurrent Computing - processes are quickly switched in and out of the CPU and memory (context switching).
  2. Parallel Computing - execution occurs at the same instant, on different processors or cores (Appropriate for CPU-Bound Processes).
  3. Asynchronous computing - a task is spawned to a different unit of processing and a signal is raised when the task is complete (Appropriate for IO-Bound Processes).

Some implementations of asynchronous operations involve multiple threads, while other operate on a simple thread. For example, JavaScript is single-threaded and asynchronous. However for languages that do support multi-threading (C#, Java, etc.), an asynchronous operation does not necessarily always create a new thread. In C#, the only point at which asynchronous operations will create threads is if a completion handler (i.e. AsyncCallback) was specified . If specified, a thread pool thread will be used to call the completion handler. But the thread is only created after the task has finished, to notify the initiator the task has completed. In common practice, C# async operations almost always specify a completion handler, which is probably why if it often assumed all async operations in C# create threads.

The Asynchronous Programming Model (APM) promotes using the same thread to process multiple requests, sequentially, but with no request blocking the thread. In C#, asynchronous operations can be performed on any method that returns a Task. The asynchronous operation is performed through a delegate with the BeginInvoke and EndInvoke methods (the asynchronous versions of the Invoke() and End()( methods).To simplfy coding C# provides built-in asynchronous methods with follow the convention of having a name which ends in "Async" (e.g. xxxxxxAsync).

Async in C# 5.0 Unleash the Power of Async

Book recommendations

Async in C# 5.0 Unleash the Power of Async, Alex Davies, O'Reilly Media, September 2012, Print ISBN:978-1-4493-3716-2| ISBN 10:1-4493-3716-3.

Pro Asynchronous Programming with .NET, Richard Blewett and Andrew Clymer, Apress, 2013, ISBN13: 978-1-4302-5920-6.


Async Method with Callback

.Async Method with Callback
Async Method with Callback

using System;
using System.Threading;
using System.Diagnostics;


namespace DelegateCallback
{
    delegate void TheDelegate(string s);

    static class StatClass
    {
        public static bool AsychMethodIsFinished { get; set; }
        public static bool CallBackIsFinished { get; set; }

        static StatClass() { CallBackIsFinished = AsychMethodIsFinished = false; }
       
        static void CallWhenFinished(IAsyncResult asyncRes)
        {
            System.Console.WriteLine("CallWhenFinished: Started on thread id: {0} at: {1}",
                                      Thread.CurrentThread.ManagedThreadId,
                                      DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            System.Threading.Thread.Sleep(3000);

            // Passed original delegate in the asyncState parameter
            TheDelegate parmDelegate = (TheDelegate)asyncRes.AsyncState;
            parmDelegate.EndInvoke(asyncRes);

            Console.WriteLine("Asynchronous Call Completed.");
            System.Console.WriteLine("CallWhenFinished: Ended on thread id: {0} at: {1}",
                                      Thread.CurrentThread.ManagedThreadId,
                                      DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            CallBackIsFinished = true;
        }


        public static void DelMethod(TheDelegate parmDelegate)
        {
            System.Console.WriteLine("DelMethod: Started on thread id: {0} at: {1}",
                                      Thread.CurrentThread.ManagedThreadId,
                                      DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            /******************************
             * Asynchronous Delegate Call *
             ******************************/
            // Send delegate object as state parameter (last parm)
            IAsyncResult asyncRes = parmDelegate.BeginInvoke("I am the Delegate Parameter - Asynchronous", new AsyncCallback(CallWhenFinished), parmDelegate);

            // 5 Seconds of Work
            for (int i = 0; i < 5; i++)
                System.Threading.Thread.Sleep(1000);

//            parmDelegate.EndInvoke(asyncRes);
            System.Console.WriteLine("\nDelMethod: Ended on thread id: {0} at: {1}",
                                      Thread.CurrentThread.ManagedThreadId,
                                      DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
        }
    }

    class Program
    {
        static void Header()
        {
            System.Console.WriteLine("*********************************************************");
            System.Console.WriteLine("***        Asynchronous Method with Callback         ***");
            System.Console.WriteLine("*********************************************************\n");
        }

        static void TheMethod(string s)
        {
            System.Console.WriteLine("TheMethod: Started on thread id: {0} at: {1}",
                          Thread.CurrentThread.ManagedThreadId,
                          DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            Console.WriteLine(s);

            // 10 Seconds of Work
            int i;
            for (i = 0; i < 10; i++)
                System.Threading.Thread.Sleep(1000);

            System.Console.WriteLine("TheMethod: Ended on thread id: {0} at: {1}",
                          Thread.CurrentThread.ManagedThreadId,
                          DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            StatClass.AsychMethodIsFinished = true;
        }


        static void Main()
        {
            Stopwatch myStopWatch = new Stopwatch();
            myStopWatch.Start();
            Program.Header();
            System.Console.WriteLine("Main: Started on thread id: {0} at: {1}",
                          Thread.CurrentThread.ManagedThreadId,
                          DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));

            // Define the delegate
            TheDelegate myDelegate1 = new TheDelegate(TheMethod);

            // Invoke the delegate
            StatClass.DelMethod(myDelegate1);

            int waitSeconds = 0;
            while ((!StatClass.CallBackIsFinished) && (waitSeconds < 30))
            {
                if (!StatClass.AsychMethodIsFinished)
                    Console.WriteLine("Main: Waiting for asych method to finish");
                else
                    Console.WriteLine("Main: Waiting for callback to finish");
               waitSeconds++;
               System.Threading.Thread.Sleep(1000);
            }
            System.Console.WriteLine("Main: Ended on thread id: {0} at: {1}",
                          Thread.CurrentThread.ManagedThreadId,
                          DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo));
            myStopWatch.Stop();
            System.Console.WriteLine("\nTotal run time is: {0}\n", myStopWatch.Elapsed);
        }
    }
}

Top


Reference Articles

Top