可重用异步 HttpHandler 的模式

发布于 2024-08-20 13:45:25 字数 1719 浏览 14 评论 0原文

我目前正在开发一个自定义 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 应该为 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 处理程序方面更有经验的人进行验证。

提前致谢!

I'm currently developing a custom HttpHandler (for compressing/combining CSS, but that doesn't matter for this question).

I started with a simple reusable=true synchronous HttpHandler like we all know.

Now i'm trying to improve it to an asynchronous handler (as it uses IO functionality and it's used on a very busy website).

My first attempt (and this seems to work ok):

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
}

This is a non-reusable httphandler (as from what I read, IsReusable should be false, because this handler has state (the asyncProcessRequest field).

Now I want to make this reusable. So my first thought was to create a dictionary of IAsyncResult / Action like this:

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);
    }
}

Is this a correct pattern ? or am I way off?

It seems to work (I'm not getting any errors or weird behavior), but before putting this to production, I would like to verify with someone who has more experience than me in writing these Http handlers..

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橪书 2024-08-27 13:45:25

一般来说,对于异步模式,您应该使用传入 BeginXxx 方法的状态参数作为最后一个参数(您将其称为 extraData)。

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

但是,在您的具体情况下,我相信您不会使用异步模式来加速任何事情。虽然它有效,但它基本上只会增加开销,因为您以异步方式调用委托,它除了分派对线程池的调用来处理调用之外什么也不做。因此,只要您没有通过异步调用同时运行多个委托,您就不会受益匪浅。由于网络请求已经是多线程的,我认为这不会有助于性能;相反,您会遇到线程池饥饿的风险。

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

In general, for the async pattern, you should use the state parameter which you pass into the BeginXxx method as last parameter (you called it extraData).

So you may want to create a helper class holding the (original) extraData as well as whatever additional state you need to handle the request end.

However, in your specific case, I believe that you're not accelerating anything with the use of the async pattern. While it works, it basically only adds overhead, since you're calling a delegate in an async fashion, which does nothing but dispatch a call to the thread pool to handle the call. Therefore, as long as you don't have multiple delegates running simultaneously via async calls, you're not going to benefit much. Since web requests are multithreaded already, I don't think that this will help performance; in the contrary, you run into the risk of threadpool starvation.

Correct and efficient async handling is not easy. You can benefit from it if you're doing inherently async things such as reading data from a file or network connection or when calling external components which support async invocation (such as a web service call or a database).

醉酒的小男人 2024-08-27 13:45:25

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

If I remember correctly IsReusable indicates to ASP.NET that your handler should not be destroyed after processing request and the same instance could be used for processing subsequent requests. I.e. one instance of the handler object does not handle multiple requests simultaneously.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文