这种情况是Task
,async
和await
真正闪耀的地方。这是相同的示例,经过重构以充分利用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
上面的)。
真正酷的是async
它在执行后台操作时不占用任何线程:
- 一个 ASP.NET 请求线程启动请求,并开始使用
WebClient
.
- 在下载过程中,
await
实际从方法中返回async
,离开请求线程。该请求线程返回到线程池 - 留下 0(零)个线程为该请求提供服务。
- 当下载完成时,该
async
方法在请求线程上恢复。该请求线程仅用于编写实际响应。
这是最佳的线程解决方案(因为需要一个请求线程来编写响应)。
原始示例还以最佳方式使用线程 - 就线程而言,它与async
基于 - 的代码相同。但 IMO 的async
代码更容易阅读。
如果您想了解更多关于的信息,我的博客上async
有一篇介绍文章。