Kamran Khan
Kamran Khan

Reputation: 9986

Parallel(Async) tasks using Web Service to avoid Threads

I have a task that I perform in parallel; for instance printing user selected documents async'ly. One way may be to use a worker thread. But thinking of the scenario where thousands of requests pouring in onto the web server, and application is spawning one more thread for printing sounds horrible. And what if all of the concurrent users start printing?

So is the reason I want to avoid worker threads.

To work around, I have moved the code in a web service; I am calling the PrintAsync() method, and I have subscribed to OnPrintComplete to get notified. Now I can send as many prints as I want without worrying about asp.net thread starvation or blocking requests.

I know web services internally use threading, but that is IOCP threads, which means it will not bother the asp.net worker threads.

I couldn't think of possible cons, except that it will be a web service.

Is this a good approach? What would have been a better alternate version of handling this functionality?

Upvotes: 2

Views: 3415

Answers (2)

Chris
Chris

Reputation: 7359

what about the Microsoft Message Queue (MSMQ)?

With this architecture, you can queue up all printing requests, and then use a windows service to receive and process on after another.

It is pretty easy to setup up and supports distributed transactions.

MSMQ on MSDN

Upvotes: 1

Drew Marsh
Drew Marsh

Reputation: 33379

So you've described how you're making async calls on the client and there's actually some more questions I would ask about how you're actually being completely async there, but it seems like your question is more about how to be as efficient as possible on the service side, right?

If you're performing long running or I/O bound operations in your service operations, you absolutely must begin to leverage WCF's support for asynchronous service operations. Now, there's lots of ways to do this, but if you're on .NET 4.0 there's no better way than using the Task Parallel Library (TPL).

First, by offloading the work to a TPL thread you free up WCF I/O threads to handle more calls. This way your long running WCF operations don't tie up WCF's ability to field other operations.

Second, the TPL leverages the a thread pool by default. You don't have to worry about every operation spinning up it's own thread and eventually starving the machine of resources. The TPL is also smart enough to spread the work across all the cores on the box way more efficiently than you could ever do yourself without a significant investment in writing plumbing code.

Third, the TPL can be combined with the traditional Asynchronous Programming Model (APM) so that if you're working with things like Streams (network or file) you can use their BeginRead/Write methods to leverage async I/O to the max which will free up the CPU threads while blocking on reads/writes. You should absolutely be doing this to achieve maximum efficiency even if you're not using the TPL, the TPL just makes it easier.

Here's a "bare bones" example of how you can use the TPL to implement an async service operation:

public IAsyncResult BeginSomeLongRunningOperation(string sampleParam, AsyncCallback callback, object asyncState)
{
    Task<int> processingTask = Task<int>.Factory.StartNew(
        _ =>
        {
             ... perform insanely long running operation here ...

             return 42;    
        },
        asyncState);

    // If there was a callback, we have to invoke it after the processing finishes
    if(callback != null)
    {
        processingTask.ContinueWith(
            _ =>
            {
                callback(calculationTask);                   
            },
            TaskContinuationOptions.ExecuteSynchronously);
    }

    return processingTask;
}

public int EndSomeLongRunningOperation(IAsyncResult asyncResult)
{
    return ((Task<int>)asyncResult).Result;
}

Upvotes: 5

Related Questions