Решено:
Я нашел решение для этого. Не знаю, почему это происходит, но Переключение типа пула приложений с «интегрированного» на «классический» решает проблему. Теперь «Выполнение запросов» продолжает расти, фактический поток процесса пула приложений остается низким (~ 31 потоков), а приложение очень отзывчиво (как и должно быть).
Я использую .Net 2.0, так что, возможно, там есть проблема - попытался найти ее в Google, но безуспешно.
См. Ответ Джо Энзмингера для объяснения
Спасибо всем еще раз.
пс. код используется для игры в пул (бильярд) онлайн - Windows (бесплатная) версия здесь для всех, кому интересно и достаточно смело, чтобы попробовать:)
<Ч />
Здравствуйте,
Я реализовал IHttpAsyncHandler, который клиентские приложения «опрашивают» для ожидания уведомлений сервера. Уведомления генерируются другими «действиями» на сервере, и Async Handler вообще не работает.
Шаги выполнения:
IHttpAsyncHandler.BeginProcessRequest
Create AsyncResult instance and add it to a "registered clients" collection
return the AsyncResult
... при другой активности сервера будут генерироваться уведомления для отправки зарегистрированным клиентам ...
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.
Проблема:
Я проверял это на IIS7 на виртуальной машине с Windows Server 2008 с пакетом обновления 2 (SP2) и 1 ядром процессора. После того, как 12 клиентов зарегистрировались для уведомлений (используя HTTP GET на Async.ashx), производительность снизилась до такой степени, что последующие клиенты не могут подключиться.
Когда я проверяю счетчики производительности ASP.NET, счетчик «Выполнение запросов» увеличивается с каждой регистрацией клиента и остается равным 12 (что, по-видимому, является его максимальным значением - возможно, размером пула потоков на процессор).
Я нахожу это очень запутанным. Хотя весь смысл асинхронных обработчиков состоит в том, чтобы освободить потоки для других соединений. Похоже, что это не так, поэтому я, должно быть, делаю что-то не так!
Почему ASP.NET потребляет поток во время ожидания завершения моего AsyncResult? Это проблема с конфигурацией? Нужно ли делать что-то конкретное, чтобы указать, что это Async Handler?
Спасибо,
Никос.
Редактировать: Добавленный код ниже:
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; } }
}