Шаблон для многоразового асинхронного HttpHandler - PullRequest
6 голосов
/ 05 февраля 2010

В настоящее время я разрабатываю собственный HttpHandler (для сжатия / объединения CSS, но для этого вопроса это не имеет значения).

Я начал с простого многоразового = истинного синхронного HttpHandler, как мы все знаем.

Теперь я пытаюсь улучшить его до асинхронного обработчика (поскольку он использует функции ввода-вывода и используется на очень загруженном веб-сайте).

Моя первая попытка (и, похоже, это работает нормально):

Action<HttpContext> asyncProcessRequest;

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
    asyncProcessRequest = new Action<HttpContext>(ProcessRequest);
    return asyncProcessRequest.BeginInvoke(context, cb, extraData);
}

public void EndProcessRequest(IAsyncResult result)
{
    asyncProcessRequest.EndInvoke(result);
}

public virtual void ProcessRequest(HttpContext context)
{
    // real work
}

Это неиспользуемый http-обработчик (поскольку из того, что я прочитал, IsReusable должен иметь значение false, поскольку у этого обработчика есть состояние (поле asyncProcessRequest).

Теперь я хочу сделать это многоразовым. Поэтому моей первой мыслью было создать словарь IAsyncResult / Action, подобный этому:

IDictionary<IAsyncResult, Action<HttpContext>> asyncProcessRequests;

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
    if (asyncProcessRequests == null)
    {
        asyncProcessRequests = new Dictionary<IAsyncResult, Action<HttpContext>>();
    }

    var request = new Action<HttpContext>(ProcessRequest);
    var result = request.BeginInvoke(context, cb, extraData);
    asyncProcessRequests.Add(result, request);
    return result;
}

public void EndProcessRequest(IAsyncResult result)
{
    Action<HttpContext> action;
    if (asyncProcessRequests.TryGetValue(result, out action))
    {
        action.EndInvoke(result);
    }
}

Это правильный шаблон? или я далеко?

Кажется, это работает (я не получаю никаких ошибок или странного поведения), но прежде чем приступить к работе, я хотел бы проверить с кем-то, кто имеет больше опыта, чем я в написании этих обработчиков Http ..

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 05 февраля 2010

Как правило, для асинхронного шаблона вы должны использовать параметр состояния, который вы передаете в метод BeginXxx в качестве последнего параметра (вы назвали его extraData).

Таким образом, вы можете создать вспомогательный класс, содержащий (оригинал) extraData, а также любое дополнительное состояние, необходимое для обработки конца запроса.

Однако в вашем конкретном случае я считаю, что вы ничего не ускоряете с использованием асинхронного шаблона. Хотя он работает, он в основном только добавляет накладные расходы, поскольку вы вызываете делегат асинхронным способом, который не выполняет ничего, кроме отправки вызова в пул потоков для обработки вызова. Поэтому, если у вас нет нескольких делегатов, работающих одновременно через асинхронные вызовы, вы не получите большой выгоды. Поскольку веб-запросы уже многопоточные, я не думаю, что это поможет производительности; напротив, вы рискуете голодом из пула потоков.

Правильная и эффективная асинхронная обработка не легка. Вы можете извлечь из этого пользу, если вы делаете по своей сути асинхронные операции, такие как чтение данных из файла или сетевого подключения, или при вызове внешних компонентов, которые поддерживают асинхронный вызов (например, вызов веб-службы или базы данных).

2 голосов
/ 05 февраля 2010

Если я правильно помню, IsReusable указывает ASP.NET, что ваш обработчик не должен быть уничтожен после обработки запроса, и этот же экземпляр можно использовать для обработки последующих запросов. То есть один экземпляр объекта-обработчика не обрабатывает несколько запросов одновременно.

...