0

I've seen 2 flavors of working with asyncronous operations in mvc controllers.

First:

public void GetNewsAsync()
{
    AsyncManager.OutstandingOperations.Increment();
    using (ManualResetEvent mre = new ManualResetEvent(false))
    {
        //Perform the actual operation in a worker thread
        ThreadPool.QueueUserWorkItem((object _mre) =>
        {
            //do some work in GetFeed that takes a long time
            var feed = GetFeed();

            AsyncManager.Parameters["Feed"] = feed;
            AsyncManager.OutstandingOperations.Decrement();
            mre.Set();

        }, mre);

        //Wait for the worker thread to finish
        mre.WaitOne(TimeSpan.FromSeconds(SomeNumberOfSecondsToWait));
    }
}

Second:

public void GetNewsAsync()
{
    AsyncManager.OutstandingOperations.Increment();

    //Perform the actual operation in a worker thread
    ThreadPool.QueueUserWorkItem((object x) =>
    {
        //do some work in GetFeed that takes a long time
        var feed = GetFeed();

        AsyncManager.Parameters["Feed"] = feed;
        AsyncManager.OutstandingOperations.Decrement();

    }, null);
}

The first blocks GetNewsAsync for SomeNumberOfSecondsToWait, the second does not. Both perform the work inside a of a worker thread and the results passed to GetNewsCompleted.

So my question is, which is the correct way to handle an Ajax call to GetNews; Wait, or don't wait?

Paul Rivera
  • 525
  • 1
  • 8
  • 20

1 Answers1

2

I don't know where did you see the first example but that's a total anti-pattern that completely defeats the purpose of an asynchronous controller. The whole point of an asynchronous operation is to execute asynchronously and free the main thread as fast as possible.

This being said if GetFeed is a blocking call (which is what its name supposes it is) you get strictly 0 benefit from an asyncrhonous controller so the second example is also wrong for me. You could use a standard synchronous controller action in this case. With the second example you draw a thread from the pool and instead of blocking inside the main thread you block inside the other thread so the net effect is almost the same (in reality it's worse) if you had used a standard synchronous controller action.

So both those examples will bring more overhead than any benefit.

Where asynchronous controllers are useful is when you have some I/O intensive API such as a database or web service call where you could take advantage of IO Completion Ports. The following article provides a good example of this scenario. The newsService used there is providing real asynchronous methods and there is no blocking during the I/O network call. No worker thread being jeopardized.

I would also recommend you reading the following article. Even if it is for classic WebForms it still contains some very useful information.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • GetFeed does not necessarily have to be a blocking call, it could likely have it's own timing/timeout handling. The point is, it could take 1 second to return, or 1 minute. As for the use of the first, I saw it in an implementation of a chat server using ajax long polling, like comet does. – Paul Rivera Nov 22 '11 at 19:24
  • @PaulRivera, if `GetFeed` was a non-blocking call you wouldn't be able to use its results immediately after calling it as you do in your second example. You will not be able to assign the `feed` result to the `AsyncManager.Parameters` immediately after calling the `GetFeed`. A non-blocking API works with callbacks. It doesn't return results. So either `GetFeed` is blocking or your second example is incorrect. – Darin Dimitrov Nov 22 '11 at 19:29
  • Ok, so GetFeed blocks for x number of seconds while waiting for something to happen. What I really need to know is whether or not the first example is correct, specifically, for ajax long polling scenarios. I mean, if there is no Wait inside of the Async method, is it safe to say the ajax call won't return until the Completed method returns data? – Paul Rivera Nov 22 '11 at 19:40
  • @PaulRivera, no the first example is incorrect. If you need to perform long polling you should not use threads from the thread pool. – Darin Dimitrov Nov 22 '11 at 19:55