Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
472 views
in Technique[技术] by (71.8m points)

iis 7 - Problem with IHttpAsyncHandler and ASP.NET "Requests Executing" counter

Solved:

I found the solution to this. Not sure why it happens but Switching the application pool type to 'classic' from 'integrated' solves the problem. Now the 'Requests Executing' keeps going up, the actual application pool process thread remains low (~31 threads) and the app is very responsive (as it should be).

I'm using .Net 2.0 so maybe there is an issue there - tried to google it but no luck.

See Joe Enzminger's reply for an explanation
Thank you all again.

ps. the code is used for playing pool (billiards) online - windows (free) version here for anyone curious and brave enough to try :)

Hello,

I've implemented an IHttpAsyncHandler that client applications "poll" to wait for server notifications. Notifications are generated by other "activities" on the server and the Async Handler does no work at all.

The execution steps are:

IHttpAsyncHandler.BeginProcessRequest

    Create AsyncResult instance and add it to a "registered clients" collection

    return the AsyncResult

...other server activity will generate notifications to be sent to registered clients...

AsyncResult.CompleteCall called as a result of the generated notification(s).

IHttpAsyncHandler.EndProcessRequest is called

    The notification(s) attached to the AsyncResult are written to the response stream.

The problem:

I've tested this on IIS7 on a VM with Windows Server 2008 SP2 and 1 cpu core. After 12 clients register for notifications (using an HTTP GET on the Async.ashx) the performance is degraded to the point that subsequent clients cannot connect.

When I check the ASP.NET performance counters the "Requests Executing" counter goes up with each client registration and stays at 12 (which appears to be its maximum value - probably a thread pool size per CPU).

I find this very confusing. I though the whole point of async handlers is to free up threads for other connections. It appears that this is not the case so I must be doing something wrong!

Why is ASP.NET consuming a thread while waiting for my AsyncResult to complete? Is this a config issue? Do I need to do something specific to indicate that this is an Async Handler?

Thank you, Nikos.

Edit: Added code below:

public class AsyncResult : IAsyncResult
{
    private AsyncCallback _cb;
    private object _state;
    private ManualResetEvent _event;
    private bool _completed;
    private bool _completedsynchronously;
    private HttpContext _context;
    private byte[] _data;
    private int _datalength;
    private object _lock = new object();

    public AsyncWaitResult(AsyncCallback cb, object state, HttpContext context)
    {
        _context = context;
        _cb = cb;
        _state = state;
    }

    public void Close()
    {
        if (_event != null)
        {
            _event.Close();
            _event = null;
        }
    }

    public HttpContext Context { get { return _context; } }
    public Object AsyncState { get { return _state; } }
    public bool CompletedSynchronously { get { return _completedsynchronously; } }
    public bool IsCompleted { get { return _completed; } }
    public byte[] Data { get { return _data; } }
    public int DataLength { get { return _datalength; } }

    public WaitHandle AsyncWaitHandle
    {
        get
        {
            lock (_lock)
            {
                if (_event == null)
                    _event = new ManualResetEvent(_completed);

                return _event;
            }
        }
    }

    public void CompleteCall(byte[] data, int length, bool completedsynchronously)
    {
        _data = data;
        _datalength = length;
        _completedsynchronously = completedsynchronously;

        lock (_lock)
        {
            _completed = true;
            if (_event != null)
                _event.Set();
        }

        if (_cb != null)
            _cb(this);
    }
}


public class Outbound : IHttpAsyncHandler
{
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object state)
    {
            AsyncResult asyncresult = new AsyncResult(cb, state, context);

            RegisteredClients.Instance.Add(asyncresult);

            return asyncresult;
    }

    public void EndProcessRequest(IAsyncResult ar)
    {
        AsyncResult result = (AsyncResult)ar;
        if (result != null)
        {
            result.Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            result.Context.Response.ContentType = "application/octet-stream";
            result.Context.Response.AddHeader("Connection", "keep-alive");

            if (result.Data != null)
                result.Context.Response.OutputStream.Write(result.Data, 0, result.DataLength);

            result.Close();
        }
    }

    public void ProcessRequest(HttpContext context){}

    public bool IsReusable { get { return true; } }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a blog post that explains what you are seeing:

http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx

and companion post

http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

In integrated pipeline mode, using the default configuration, IIS7 places a limit of 12 concurrent REQUESTS (not threads) per CPU. You can change this by modifying the configuration.

I couldn't let it go. I'm pretty sure this is what you're seeing. Deep diving into the article, I don't really like the change they made because it clearly causes problems like this, but who am I to judge!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...