Asynchronous Programming Model: In Chasing The Ideal

There are many uses for concurrent in C#. In this and subsequent posts, we will talk about asynchronous programming.

Asynchronous programming lies in the fact that the result of the function execution is not available immediately, but after some time in the form of some asynchronous call.

The first Asynchronous API in C# was the so-called APM (Asynchronous Programming Model).

This old pattern for asynchronous programming uses the IAsyncResult design pattern. In some .NET libraries we come across BeginXXX(BeginOperationName) and EndXXX(EndOperationName) methods, these methods together help us to use APM.

static void Main(string[] args)
{
    FileStream fs = new FileStream("Sdfsf", FileMode.Open);
    byte[] array = new byte[fs.Length];
    //start async operation and return handle.. line 17...
    IAsyncResult asyncResult = fs.BeginRead(array,0, (int)fs.Length, null, null);
    //emulating some other operations
    Thread.Sleep(1000);
    //wait here if operation already not completed
    fs.EndRead(asyncResult);
}

The difference between asynchronous and multithreaded programming is that Asynchronous methods are designed for non-blocking operations. We use asynchronous programming when we need to work with input and output devices. This is when we work with databases, various files, or with the network.

APM is no exception in this situation.

PS: For more info about the differences between multithread, async, and parallel programming please read here.

So, let's study how our code works to handle descriptor d() line, we asynchronously call the file to be read. In this case, our main thread is non-blocking! The fact is that when we call something asynchronously, the request is sent to the device-device handler. In our situation, this is the OS file system, and it does not matter to us how the request will be processed. We sent the command and without waiting for it, we continue to work in our main thread.

It can be seen that our main thread is not yet busy with this work. But we have to get the answer somehow. We need some kind of handle-descriptor, the role of this descriptor is played by IAsyncResult, after calling BeginRead() the method instantly returns IAsyncResult and continues to work. Until EndRead() is called, our method (BeginRead in this situation) continues to run asynchronously. The EndRead() method forces our main thread to stop and wait for the result of the asynchronous method execution. If the asynchronous method has finished running before EndRead() is called, then there will be no delay and the program will continue normally.

Asynchronous programming also includes asynchronous delegates.

Asynchronous delegates allow you to call the methods that these delegates point to asynchronously. If we want to execute a certain method asynchronously, then this approach is also not bad for older versions of .NET.

Func<decimal, decimal, decimal> func = (x, y) =>
{
     //enumating some big operation here..
     Thread.Sleep(2000);
     return x * y;
};

IAsyncResult delAsyncResult = func.BeginInvoke(45, 67, null, null);
//emulating some other operations
Thread.Sleep(1000);

//wait here and get result
decimal result = func.EndInvoke(delAsyncResult);

Asynchronous delegates allow you to call the methods that these delegates point to asynchronously.

The BeginInvoke method in our situation takes 4 parameters. The first two arguments are clear. The third parameter represents the System.AsyncCallback delegate. AsyncCallback points to a method that will be executed as enumerating the completion of the. synchronous delegate. In this case, we ignore it and pass null in its place.

The 4th parameter represents an object with which we can pass additional information to the finalizer specified in the previous parameter. This object stores information about the asynchronous operation. Then we pass this object to the the EndInvoke method and get the result.

static void Main(string[] args)
{

    Func<decimal, decimal, decimal> func = (x, y) =>
    {
        //enumating some big operation here..
        Thread.Sleep(2000);
        return x * y;
    };

   IAsyncResult delAsyncResult = func.BeginInvoke(45, 67, MyCallBack, "operation completed successfully");

    //emulating some other operations
    Thread.Sleep(1000);

    //wait here and get result
   decimal result = func.EndInvoke(delAsyncResult);
    Console.ReadLine();
}

private static void MyCallBack(IAsyncResult ar)
{
    string message =  ar.AsyncState.ToString();
    Console.WriteLine(message);
}


Similar Articles