asp.net - 在 IHttpAsyncHandler 中使用 Task 或 async/await

标签 asp.net threadpool task-parallel-library async-await ihttpasynchandler

自从开始编写 ASP.NET 应用程序时,当我想添加线程时,我可以通过 3 种简单的方法在 ASP.NET 应用程序中完成线程:

  • 使用System.Threading.ThreadPool
  • 使用自定义委托(delegate)并调用其 BeginInvoke 方法。
  • 借助 System.Threading.Thread 类使用自定义线程。

前两种方法提供了一种为应用程序启动工作线程的快速方法。但不幸的是,它们会损害应用程序的整体性能,因为它们消耗来自 ASP.NET 用来处理 HTTP 请求的同一池中的线程

然后我想使用一个新的Task或者async/await来编写IHttpAsyncHandler。您可以找到 Drew Marsh 在这里解释的一个示例:https://stackoverflow.com/a/6389323/261950

我的猜测是,使用 Task 或 async/await 仍然会消耗 ASP.NET 线程池中的线程,而且我不希望这样做,原因很明显。

您能否告诉我我是否可以在后台线程上使用任务(异步/等待),就像使用 System.Threading.Thread而不是来自线程池

预先感谢您的帮助。

托马斯

最佳答案

这种情况是 Taskasyncawait 真正发挥作用的地方。下面是同一个示例,经过重构以充分利用 async(它还使用我的 AsyncEx 库中的一些辅助类来清理映射代码):

// First, a base class that takes care of the Task -> IAsyncResult mapping.
// In .NET 4.5, you would use HttpTaskAsyncHandler instead.
public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler
{
    public abstract Task ProcessRequestAsync(HttpContext context);

    IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        var task = ProcessRequestAsync(context);
        return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData);
    }

    void EndProcessRequest(IAsyncResult result)
    {
        Nito.AsyncEx.AsyncFactory.ToEnd(result);
    }

    void ProcessRequest(HttpContext context)
    {
        EndProcessRequest(BeginProcessRequest(context, null, null));
    }

    public virtual bool IsReusable
    {
        get { return true; }
    }
}

// Now, our (async) Task implementation
public class MyAsyncHandler : HttpAsyncHandlerBase
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
        using (var webClient = new WebClient())
        {
            var data = await webClient.DownloadDataTaskAsync("http://my resource");
            context.Response.ContentType = "text/xml";
            context.Response.OutputStream.Write(data, 0, data.Length);
        }
    }
}

(如代码中所述,.NET 4.5 有一个 HttpTaskAsyncHandler ,与上面的 HttpAsyncHandlerBase 类似)。

关于异步真正酷的一点是,它在执行后台操作时不占用任何线程:

  • ASP.NET 请求线程启动请求,并开始使用 WebClient 下载。
  • 在下载过程中,await 实际上从 async 方法返回,离开请求线程。该请求线程将返回到线程池 - 留下 0()个线程来服务该请求。
  • 下载完成后,async 方法将在请求线程上恢复。该请求线程仅用于编写实际响应。

这是最佳线程解决方案(因为需要请求线程来写入响应)。

原始示例也以最佳方式使用线程 - 就线程而言,它与基于async的代码相同。但在我看来,async 代码更容易阅读。

如果您想了解有关异步的更多信息,我有一个 intro post在我的博客上。

关于asp.net - 在 IHttpAsyncHandler 中使用 Task 或 async/await,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9225420/

相关文章:

asp.net - 如何在 DataBound 事件上/之前捕获错误

c# - 如何从 ViewStart 中访问(自定义)Web 助手?

Java 8 顺序流非常高地增加了 CPU 使用率

c# - 为什么通过调用 Task.Run 和 ThreadPool.QueueUserWorkItem 排队到 ThreadPool 时,线程数会增加一个以上?

c# - 单元测试 - 如何检查类是否并行访问外部资源?

c# - 在 .NET 中使用 TPL

c# - 编写一个 Task.WhenAll/WhenAny 变体,取消第一个故障/取消任务上的所有其他任务

c# - 存储过程 EF 和 NET CORE

java - 使用 Jest 的服务在线程池上阻塞,为什么?

c# - 禁用asp.net中div内的所有控件