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 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…