Проблема с IHttpAsyncHandler и счетчиком ASP.NET «Выполнение запросов» - PullRequest
2 голосов
/ 25 мая 2011

Решено:

Я нашел решение для этого. Не знаю, почему это происходит, но Переключение типа пула приложений с «интегрированного» на «классический» решает проблему. Теперь «Выполнение запросов» продолжает расти, фактический поток процесса пула приложений остается низким (~ 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; } }
}

Ответы [ 2 ]

3 голосов
/ 25 мая 2011

Вот сообщение в блоге, которое объясняет, что вы видите:

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

и сопутствующее сообщение

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

В интегрированномВ конвейерном режиме, используя конфигурацию по умолчанию, IIS7 устанавливает ограничение 12 одновременных ЗАПРОСОВ (не потоков) на ЦП.Вы можете изменить это, изменив конфигурацию.

Я не мог отпустить.Я уверен, что это то, что вы видите.Углубившись в эту статью, мне не очень нравится то изменение, которое они внесли, потому что оно явно вызывает подобные проблемы, но кто я такой, чтобы судить!

1 голос
/ 25 мая 2011

Еще одна вещь, чтобы проверить.Если ваш клиент не является реальным браузером, а скорее другим приложением, которое делает несколько одновременных запросов к вашему серверу, это может вызвать вашу проблему.

Параллельные запросы и состояние сеанса

Доступ к сеансу ASP.NETсостояние является исключительным для каждого сеанса, что означает, что если два разных пользователя делают параллельные запросы, доступ к каждому отдельному сеансу предоставляется одновременно.Однако, если два одновременных запроса сделаны для одного и того же сеанса (с использованием одного и того же значения SessionID), первый запрос получает эксклюзивный доступ к информации сеанса.Второй запрос выполняется только после того, как первый запрос завершен.(Второй сеанс также может получить доступ, если исключительная блокировка информации освобождается, поскольку первый запрос превышает время ожидания блокировки.) Если значение EnableSessionState в директиве @ Page установлено в ReadOnly, запрос только для чтения.Информация о сеансе не приводит к исключительной блокировке данных сеанса.Однако запросы только для чтения для данных сеанса, возможно, все еще должны ждать блокировки, установленной запросом чтения-записи, для очистки данных сеанса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...