Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Task or async/await in IHttpAsyncHandler

Since the very begining of writing ASP.NET applications when I wanted to add a threading there are 3 simple ways I can accomplish threading within my ASP.NET application :

  • Using the System.Threading.ThreadPool.
  • Using a custom delegate and calling its BeginInvoke method.
  • Using custom threads with the aid of System.Threading.Thread class.

The first two methods offer a quick way to fire off worker threads for your application. But unfortunately, they hurt the overall performance of your application since they consume threads from the same pool used by ASP.NET to handle HTTP requests.

Then I wanted to use a new Task or async/await to write IHttpAsyncHandler. One example you can find is what Drew Marsh explains here : https://stackoverflow.com/a/6389323/261950

My guess is that using Task or async/await still consume the thread from the ASP.NET thread pool and I don't want for the obvious reason.

Could you please tell me if I can use Task (async/await) on the background thread like with System.Threading.Thread class and not from thread pool ?

Thanks in advance for your help.

Thomas

like image 550
Tomasz Jaskuλa Avatar asked Feb 10 '12 09:02

Tomasz Jaskuλa


People also ask

What is the difference between Task run and async await?

Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

Can we use async without Task?

Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.

Does await Task delay block thread?

await Task. Delay(1000) doesn't block the thread, unlike Task. Delay(1000).

Is Task run asynchronous?

NET, Task. Run is used to asynchronously execute CPU-bound code.


1 Answers

This situation is where Task, async, and await really shine. Here's the same example, refactored to take full advantage of async (it also uses some helper classes from my AsyncEx library to clean up the mapping code):

// First, a base class that takes care of the Task -> IAsyncResult mapping.
// In .NET 4.5, you would use HttpTaskAsyncHandler instead.
public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler
{
    public abstract Task ProcessRequestAsync(HttpContext context);

    IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        var task = ProcessRequestAsync(context);
        return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData);
    }

    void EndProcessRequest(IAsyncResult result)
    {
        Nito.AsyncEx.AsyncFactory.ToEnd(result);
    }

    void ProcessRequest(HttpContext context)
    {
        EndProcessRequest(BeginProcessRequest(context, null, null));
    }

    public virtual bool IsReusable
    {
        get { return true; }
    }
}

// Now, our (async) Task implementation
public class MyAsyncHandler : HttpAsyncHandlerBase
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
        using (var webClient = new WebClient())
        {
            var data = await webClient.DownloadDataTaskAsync("http://my resource");
            context.Response.ContentType = "text/xml";
            context.Response.OutputStream.Write(data, 0, data.Length);
        }
    }
}

(As noted in the code, .NET 4.5 has a HttpTaskAsyncHandler which is similar to our HttpAsyncHandlerBase above).

The really cool thing about async is that it doesn't take any threads while doing the background operation:

  • An ASP.NET request thread kicks off the request, and it starts downloading using the WebClient.
  • While the download is going, the await actually returns out of the async method, leaving the request thread. That request thread is returned back to the thread pool - leaving 0 (zero) threads servicing this request.
  • When the download completes, the async method is resumed on a request thread. That request thread is briefly used just to write the actual response.

This is the optimal threading solution (since a request thread is required to write the response).

The original example also uses threads optimally - as far as the threading goes, it's the same as the async-based code. But IMO the async code is easier to read.

If you want to know more about async, I have an intro post on my blog.

like image 54
Stephen Cleary Avatar answered Oct 07 '22 06:10

Stephen Cleary