Search code examples
c#multithreadingwcfthreadpooliocp

C# How to perform Asynchrounus I/O using Completion Ports with APM-TAP Patterns on WCF Callback?


I am trying to utilize I/O Completion Ports using WCF Callback in a Duplex Contract. I am using the following simple line to do this:

OperationContext.Current.OnPushData(data);

Where OnPushData is a callback contract operation that is implemented on the client side.
Since this line is representing a Response (Output operation) using some network interface and WCF is also relying on ThreadPool threads that can be used as a worker threads or I/O CompletionPortThread, it will be a good idea to utilize I/O CompletionPortThreads by writing to completion port using TAP or APM Patterns (As the article I referred to is suggesting) instead of using a normal worker thread which will increase the performance considerably.


Solution

  • Short Answer:
    The trick to be able to use Async I/O with Duplex WCF Contract is the following simple code:

        [OperationContract(IsOneWay = true)]
        Task OnPushData(data);
    

    Simply you need to change the return type of your callback contract method to be Task. but this is not enough, you need to implement an async method like this:

        public async Task PublishData()
        {
            communicationCallback = (ICommunicationObject)service.Callback;
            if (communicationCallback.State == CommunicationState.Opened)
            {
                    await service.Callback.OnPushData(data);
            }
        }
    

    That is all. This actually boosts the performance of my application. and Now I am able to see I/O completion Ports threads utilized calling ThreadPool.GetAvailableThreads(workers,IO)

    Some Explinations:
    As I understand, to be able to use Async I/O mechanism, you will need to do the following:

    1- Determining your I/O operation.
    2- A method that will encapsulate your async I/O logic.
    3- A callback mechanism that will be called when async I/O is finished and its purpose mainly is to get the result of the Async I/O.
    4- An object that will holds your Async I/O result.

    .NET framework provides 3 design patterns to do so:

    1- IAsyncResult Asynchrnous Pattern: where Beginxxx and Endxxx will encapsulate your async logic along with a Callback Delegate that represents the callback method and of course an IAsyncResult object used to hold your async I/O result.
    2- Task Based Asynchronous Pattern: Using one class only which is Task along with async/await keywords that facilitate the using of TAP pattern.
    3- Event Based Asynchronous Pattern.

    You can read more about how you can use these patterns with WCF Services at How to Implement an Asynchronous Service Operation

    However, The previous link is great for implementing async request/response service, though, there is no explanation on how to do so with callback contract.
    Unfortunately, in my case I have to implement a subscriber/publisher patttern using WCF framework where data publishing is initiated by the service side periodically (each 1 second).

    More Details:
    I will try to make this as short as possible:
    WCF is relying on ThreadPool provided by .NET Framework. ThreadPool has 2 kind of threads:
    1- Worker Threads: for Compute-Bound operations.
    2- I/O Completion Port Threads: Used to get the result of an I/O operation.

    You must differentiate between IOCP Thread and IOCP Object initiated by CLR. IOCP Thread role is to deliver the result of I/O operation while IOCP Object is the one initiated by CLR to recieve all I/O requests. In other words, they collaborate to achieve I/O operation.

    First thing you need to know is that any I/O request you made will result in a system call that will initiate an object Called IRP (I/O request Packet) whether you are using synchronous or asynchronous paradigm.

    I/O Completion Port (IOCP) is nothing but a queue-like object initiated by the CLR. This object is responsible for receiving all I/O Completed requests (IRPs). At this point there are 2 possibilities here:
    1- Your I/O operation is called by a synchronous method: In this case the caller thread will be blocked until your I/O operation is done.
    2- Your I/O operation is called by an async method: In this case the caller thread will continue the execution and it will not be blocked for the I/O operation until completion.

    Supposing that you are using async method, When your async I/O operation is completed, this means the IRP object is processed and now it will be queued to IOCP object. ThreadPool IOCP threads will come to play the role of pulling the relative IRP from IOCP which will be wrapped in IAsyncResult for APM or Task object for TAP and passing this object to your application Level through a Callback Mechanism.

    Some References:

    [1]: https://msdn.microsoft.com/en-us/library/ms734701.aspx
    [2]: http://blog.stephencleary.com/2012/08/async-wcf-today-and-tomorrow.html
    [3]: http://southworks.com/blog/2013/10/29/asynchronous-io-in-c-io-completion-ports/
    [4]: http://southworks.com/blog/2013/08/02/asynchronous-io-in-c-introduction/
    [5]: http://mikehadlow.blogspot.com/2011/03/7000-concurrent-connections-with.html
    [6]: https://msdn.microsoft.com/en-us/library/ms731177(v=vs.110).aspx
    [7]: http://www.amazon.es/Clr-Via-C-Developer-Reference/dp/0735667454