zoukankan      html  css  js  c++  java
  • ASP.NET页面剖析异步页面

        ASP.NET页面会被HTTP处理程序作为Page类的实例处理。每个请求会占用ASP.NET线程池中的一个线程,在请求完毕后该线程才会被释放。如果被请求的页面频繁地启动外部的、高耗时的任务时,经常会出现ASP.NET进程闲置,但池中没有空闲的线程来处理新入的其他页面的请求。这种情况下,创建异面页面可以减轻这个问题。

        异步ASP.NET页面的构建涉及两个方面: @Page指令的一个新属性Async,以及注册若干异步执行的任务。异步任务可以通过两种途径注册:一种是为PreRenderComplete事件定义异步处理程序Begin/End对(AddOnPreRenderCompleteAsync方法用于将异步事件处理程序添加到页面的PreRenderComplete事件中);另一种是创建代表异步任务的PageAsyncTask对象,PageAsyncTask类代表要以异步方式执行任务(RegisterAsyncTask方法能够接受一个PageAsyncTask对象,返回void)。

    AddOnPreRenderCompleteAsyncRegisterAsyncTask的区别:

        从功能上讲,这两个方法几乎相同,二者都会将请求的执行分为两部分——分别在同步点前后。他们之间的区别在于:第一个区别在逻辑上,RegisterAsyncTask是一个用于在一个页面中运行多个异步任务的API(而不能跨越多个带有Async=true属性的异步页面),而AddOnPreRenderCompleteAsync是专门为多个异步页面设计的。RegisterAsyncTask执行End处理程序时,所处线程的上下文比AddOnPreRenderCompleteAsync所处线程的更丰富。该线程上下文包括模拟(impersonation)和HTTP上下文信息,该信息在一般异步页面的End处理程序所处线程中不存在。此外,RegisterAsyncTask还允许设置超时值,确保任何任务消耗的时间不会超过指定的秒数。另一个区别在:RegisterAsyncTask有利于实现对远程源的多个调用。我们只需设置一个布尔类型的标志,便会获得并行执行的能力,而不必要自行创建并管理自定义的IAsyncResult对象。

    前台代码示例:

    View Code
     1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="StreamDownload.aspx.cs" Inherits="WebTestDemo.AsyncPage.StreamDownload" Async="true" Trace="true"%>
     2 
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     4 
     5 <html xmlns="http://www.w3.org/1999/xhtml">
     6 <head runat="server">
     7     <title></title>
     8 </head>
     9 <body>
    10     <form id="form1" runat="server">
    11     <div>
    12         <%=msdnData%>
    13     </div>
    14     </form>
    15 </body>
    16 </html>

    注意:以上@Page指令的Async和Trace属性。Async属性使页面能够为PreRenderComplete事件注册异步处理程序,Trace属性使页面能够显示页面跟踪信息。

    后台代码示例:

    View Code
     1 /// <summary>
     2     /// 异步下载MSDN首页实例
     3     /// </summary>
     4     public partial class StreamDownload : System.Web.UI.Page
     5     {
     6         const string connectionToMSDN = "http://msdn.microsoft.com";
     7         private WebRequest req;
     8         public string msdnData;
     9 
    10         protected override void OnInit(EventArgs e)
    11         {
    12             //将跟踪消息写入页面跟踪日志
    13             Trace.Warn("当前线程:" + Thread.CurrentThread.ManagedThreadId.ToString());
    14         }
    15 
    16         protected void Page_Load(object sender, EventArgs e)
    17         {
    18             //AddOnPreRenderCompleteAsync方法
    19             AddOnPreRenderCompleteAsync(
    20                 new BeginEventHandler(BeginTask),
    21                 new EndEventHandler(EndTask));
    22 
    23             //RegisterAsyncTask方法
    24             //PageAsyncTask task = new PageAsyncTask(
    25             //    new BeginEventHandler(BeginTask),
    26             //    new EndEventHandler(EndTask),
    27             //    null,
    28             //    null);
    29             //RegisterAsyncTask(task);
    30         }
    31 
    32         IAsyncResult BeginTask(object sender, EventArgs e, AsyncCallback cb, object state)
    33         {
    34             Trace.Warn("开始异步 当前线程:" + Thread.CurrentThread.ManagedThreadId.ToString());
    35             //准备一个Web请求
    36             req = WebRequest.Create(connectionToMSDN);
    37             //开始操作并返回IAsyncResult对象
    38             return req.BeginGetResponse(cb, state);
    39             
    40         }
    41 
    42         void EndTask(IAsyncResult ar)
    43         {
    44             //这段代码将调用一个池里的线程
    45             string text;
    46             using (WebResponse response = req.EndGetResponse(ar))
    47             {
    48                 StreamReader reader;
    49                 using (reader = new StreamReader(response.GetResponseStream()))
    50                 {
    51                     text = reader.ReadToEnd();
    52                 }
    53                 
    54                 msdnData = ProcessFeed(text);
    55             }
    56             Trace.Warn("结束异步 当前线程:" + Thread.CurrentThread.ManagedThreadId.ToString());
    57         }
    58 
    59         protected override void OnSaveStateComplete(EventArgs e)
    60         {
    61             Trace.Warn("当前线程:" + Thread.CurrentThread.ManagedThreadId.ToString());
    62         }
    63 
    64         string ProcessFeed(string feed)
    65         {
    66             //来自XML输入,创建页面输出
    67             return Server.HtmlDecode(feed);
    68         }
    69     }

    图1:从MSDN页面下载的内容

     图2:跟踪的请求详细信息

        图2能看出,当页面加载到达PreRenderComplete阶段前,异步页面会一直执行,随后被阻塞,等待异步操作完成。当该操作最终完成后,页面会从PreRenderComplete阶段继续执行。根据ASP.NET设计,在其中有一个针对异步操作的“展开点”(unwind point)(也称为“同步点”[async point]),该点位于PreRender和PreRenderComplete事件之间。当页面接收到PreRender事件时,该同步点尚未到达。而页面接收到PreRenderComplete时,刚好超过该同步点。

        当程序处理到PreRender之后时,线程会被释放,执行外部的任务, 异步任务执行完成后,HTTP运行库会再次处理请求,即从PreRenderComplete阶段开始继续完成其页面生命周期的其他阶段(如图2中的后续步骤)。

  • 相关阅读:
    移动端web初体验
    网页布局框架
    CSS 3D翻转相册动画特效
    move.js框架
    js照片墙拖拽特效
    团队编程项目作业2-团队编程项目开发环境搭建过程
    课后作业-阅读任务-阅读提问-1
    团队编程项目作业3
    阅读提问-2
    结对编程项目作业5
  • 原文地址:https://www.cnblogs.com/PongorXi/p/2559369.html
Copyright © 2011-2022 走看看