【问题标题】:Pattern for Reusable asynchronous HttpHandler可重用异步 HttpHandler 的模式
【发布时间】:2010-02-05 15:09:52
【问题描述】:

我目前正在开发一个自定义 HttpHandler(用于压缩/组合 CSS,但这对于这个问题并不重要)。

我从一个简单的 reusable=true 同步 HttpHandler 开始,就像我们都知道的那样。

现在我正在尝试将其改进为异步处理程序(因为它使用 IO 功能并且在非常繁忙的网站上使用)。

我的第一次尝试(这似乎工作正常):

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
}

这是一个不可重用的 httphandler(根据我的阅读,IsReusable 应该是假的,因为这个处理程序有状态(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 处理程序经验的人进行验证..

提前致谢!

【问题讨论】:

  • 你确定你真的需要为每个请求压缩/压缩 CSS 吗?也许,在构建/部署期间这样做会更好?
  • ...和/或确保它被正确缓存。
  • 浏览器和文件缓存得到正确处理。但是这个问题更多的是关于 httphandler 模式 async/reusable...

标签: c# asp.net asynchronous httphandler ihttpasynchandler


【解决方案1】:

一般来说,对于异步模式,您应该使用传递给 BeginXxx 方法的 state 参数作为最后一个参数(您称之为 extraData)。

因此,您可能希望创建一个辅助类来保存(原始)extraData 以及处理请求结束所需的任何其他状态。

但是,在您的具体情况下,我相信您不会通过使用异步模式来加速任何事情。虽然它可以工作,但它基本上只会增加开销,因为您正在以异步方式调用委托,它只会向线程池发送调用以处理调用。因此,只要您没有通过异步调用同时运行多个委托,您就不会受益匪浅。由于 Web 请求已经是多线程的,我认为这不会提高性能;相反,您会遇到线程池饥饿的风险。

正确高效的异步处理并不容易。如果您正在执行固有的异步操作,例如从文件或网络连接读取数据,或者在调用支持异步调用的外部组件(例如 Web 服务调用或数据库)时,您可以从中受益。

【讨论】:

【解决方案2】:

如果我没记错的话,IsReusable 向 ASP.NET 表明您的处理程序不应在处理请求后被销毁,并且同一实例可用于处理后续请求。 IE。处理程序对象的一个​​实例不会同时处理多个请求。

【讨论】:

  • 所以不会被销毁(后续请求使用同一个实例)。但它也保证不会在同一个实例上同时发出请求……那么 asp.net 如何处理高负载?它会创建更多实例吗?还是等待当前请求完成?
  • 由于您的对象的初始化非常便宜,因此使其可重用可能不值得。如果 http 处理程序的创建成本很高(例如,如果它必须从配置文件或其他什么初始化),这是有道理的。
  • 使用IHttpAsyncHandler的要点是将分配给请求的线程返回给线程池(线程是有限的资源)。如果您的 http 处理程序是轻量级对象并且可以快速实例化,我认为与不可重用处理程序相比,可重用处理程序的性能不会有显着优势。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
  • 2017-03-13
  • 2017-09-05
  • 2014-07-19
  • 1970-01-01
  • 2015-06-26
  • 2014-07-16
相关资源
最近更新 更多