zoukankan      html  css  js  c++  java
  • ASP.NET异步处理

    摘自:http://liquorbin.blog.163.com/blog/static/911563382010225101519334/

    要想了解asp.net 2.0的异步页的处理过程,先列出页面的生命周期:

            1 :Init 事件: 页面初始化 ,初始化设置。

            2: LoadViewState方法: 加载视图状态, 填充ViewState属性。

            3 :LoadPostData方法: 处理回发数据, 处理传入窗体数据。

            4: Load 事件: 加载页面 ,页面控件初始化完成并反映了客户端的数据。

            5 :RaisePostDataChangedEvent方法: 回发更改通知 引发更改事件。

            6 :RaisePostBackEvent方法: 处理回发事件 ,处理引起回发的客户端事件,并在服务上引发相应时间。

            7: PreRender事件: 页面预呈现 。

            8 :SaveViewState方法: 保存视图状态, 将ViewState属性保存到字符串中。

            9 :Render方法: 呈现页面 。

           10: Dispose方法: 处置是否对昂贵资源的引用。

           11 :Unload事件: 卸载页面 。

        页面处理方式:

    1:同步处理;

            2:异步处理。     

          同步请求过程:

             1:ASP.NET 收到页面请求时,从线程池中提取一个线程并将请求分配给该线程。

             2:页在该请求期间保留线程,防止该线程用于处理其他请求。

             3:如果一个同步请求需要运算时间较长,此时分配给该请求的线程在调用返回之前处于挂起状态。

             4:等待线程返回后完成页面的其它生命周期。

       同步请求的生命周期和线程关系图:

    ASP.NET异步处理 - likebin - likebin的博客

          同步请求的问题:

              线程池的可用线程是有限的,如果此时请求过多,ASP.NET 因 503“Server Unavailable”错误使后续请求失败。这让asp.net能够接收的请求量会大大减少,影响了可伸缩性。

         异步的处理过程:

             前面的两点和普通同步请求一样,不同的是对于比较费时的过程的处理方式:

             1:一个异步操作开始响应 ASP.NET 的信号之后,该线程返回线程池。

             2:ASP.NET 调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法。Begin 方法的任务是启动诸如数据库查询或 Web 服务调用的异步操作,并立即返回。

             3:线程返回到线程池。同时,Begin 方法返回 IAsyncResult。

             4: ASP.NET 从线程池提取线程并调用 End 方法。

       5:当 End 返回之后,ASP.NET 执行该页生命周期其余的部分。

       异步请求的生命周期和线程关系图:

    ASP.NET异步处理 - likebin - likebin的博客

         异步的优势:         线程池线程得到了高效的使用,提高了可伸缩性。原来挂起等待的线程现在可用于服务其他请求。

        异步加载数据的示例:

             第一步:让页面支持异步。设置Async属性。

             第二步:因为是操作数据库,想让数据库支持异步,需要对数据库连接串进行配置。

                        Asynchronous Processing=true。         第三步:在页面的Page_Load事件中注册异步事件。

       

    protected void Page_Load(object sender, EventArgs e)

             {

                 AddOnPreRenderCompleteAsync(

        new BeginEventHandler(BeginAsyncOperation),

        new EndEventHandler(EndAsyncOperation)

    );

             }

    IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state)

             {

                string sql = "SELECT TOP 10 * FROM dbo.Card_Ext";

                 SqlConnection _conn = new SqlConnection(ConfigurationManager.

                 AppSettings["DataAccessContionStringRead"].ToString());            _conn.Open();

                 SqlCommand cmd = new SqlCommand(sql, _conn);

                 IAsyncResult rIsynResult = cmd.BeginExecuteReader(cb, cmd,

                CommandBehavior.CloseConnection);            return rIsynResult;

             }

            void EndAsyncOperation(IAsyncResult IResult)

             {

                if (!IResult.IsCompleted)

                 {

                     IResult.AsyncWaitHandle.WaitOne();

                 }

                else

                 {

                     SqlDataReader dr = (IResult.AsyncState as SqlCommand).EndExecuteReader(IResult);

                    if (!dr.IsClosed)

                     {

                         List<string> _list = new List<string>();

                        while (dr.Read())

                         {

                             _list.Add(dr[0].ToString());

                         }

                        this.GridView1.DataSource = _list;

                        this.GridView1.DataBind();

                     }

                     dr.Close();

                 }

             }

     

    .Net下比较常用的异步处理场景:

               1:FileStream,即我们常说的I/O操作:

               2:Socket;

               3:SqlCommand,例如:BeginExecuteReader、BeginExecuteNonQuery。

               4:WebRequest,像抓取网页等操作;

               5:WebServcie的调用。

    异步调用应该注意的地方:

              下面的程序也是合法的。这种方式虽然也是异步调用,但是和同步调用效果一样,因为EndExecuteReader方法会让当前线程挂起,直到返回结果。从性能角度和资源上讲,比直接用同步效果更差,因为系统要多启动一个线程。比较好的做法就是采用回调方式,具体做法可以参考上面的代码。

    cmd.BeginExecuteReader(CommandBehavior.CloseConnection);

    cmd.EndExecuteReader(rIsynResult);

     

          asp.net异步页面与ajax异步的效果区别:

               1:asp.net的异步页面让我第一想法是和ajax效果比较,ajax应用在比较费时的方法上,当数据加载时,在页面显示数据的区域先用一段提示文字,例如:数据正在加载中...之类的,无论这个方法多么费时,它只影响这一块的数据显示,页面其它区域不受影响(如果速度不慢的话)。而asp.net异步页面并不能达到这种效果,从上面的异步执行流程图可以看出,异步调用的事件发生在OnPreRenderComplete中,就是说在页面中生命周期之内,页面要想完全呈现给用户,必须等待异步方法返回结果。例如,一个费时的异步IO方法,需要费时10S,那么用户要想看到页面,起码在10S以上。

               2:异步页面增加的是处理请求的数量,线程池线程得到了高效的使用,提高了可伸缩性,而ajax是在页面加载完成之后根据返回结果调用回调函数操作DOM完成数据加载。

           异步任务:

                ASP.NET 2.0 中引入了另一个方法来简化异步操作: RegisterAsyncTask,比 AddOnPreRenderCompleteAsync 具有以下优势。

                1:除了 Begin 和 End 方法,RegisterAsyncTask 允许注册当异步操作长时间无法完成时调用的超时方法。设置 @ Page 指令中 AsyncTimeout 属性设置超时。

                2:可以在一个请求中多次调用 RegisterAsyncTask 来注册若干异步操作。

                3:可以使用 RegisterAsyncTask 的第四个参数将状态传递给 Begin 方法。这个参数一般设置为null。

        RegisterAsyncTask 的异步页与依赖于 AddOnPreRenderCompleteAsync 的异步页相类似。需要将该页的 AsyncMode 属性设置为 true,且与通过 PreRender 事件执行,此时调用使用 RegisterAsyncTask 注册的 Begin 方法,而不是AddOnPreRenderCompleteAsync ,而且进一步保持请求处理直到最后一个操作完成。

    那么什么情况下适合在web上使用哪种ASP.NET多线程模式呢

    我们来看看这段伪代码,他的用途是提交一个报告,方法传入一个报告,并从一个WebService中获得一些报告的内容,接着插入数据库,然后在文件服务器上生成一个报告文件,最后发出一个通知,让我们逐条命令的过一下这个方法,看看什么地方适合改为异步调用?(记得我们的讨论都是基于web的,关于桌面运用的多线程请参考 多线程总结一)

     

    1. public void CreateReport(Report report){   
    2.    
    3. //从webservice上取得报告的一些信息,  
    4. 不取得这些信息报告,报告是不完整的,是不能提交的   
    5.    
    6. Report fullreport=CallWebService(report);   
    7.    
    8. //插入数据库,很重要的工作   
    9.    
    10. InsertIntoDataBase(fullreport)   
    11.    
    12. try{   
    13.    
    14. //生成报告文件,这里是一个耗时而且容易出错的操作   
    15.    
    16. WriteStaticFile(fullreport)   
    17.    
    18. }   
    19.    
    20. catch{//记录错误日志。。。。}   
    21.    
    22. //这个只是通知邮件   
    23.    
    24. CallMailService2(fullreport)   
    25.    
    26. }   

    第一条语句CallWebService()从一个webservice里加载一些报告的内容,这个是业务逻辑相关的,因为如果不加载的话报告内容是不完整的,不能提交,显然不能改为异步调了不管的模式,在这里你可以尝试模式一,但是这个改动是没有作用的,因为其他所有的过程,包括插入数据库,生成报告都依赖于这个方法的返回,所以如果我们在这里使用异步的话,其他的所有操作都必须等待他的返回,所以采用异步除了多增加了线程以外,一点时间也不能节省

    再来看插入数据库,和上面一样也没有必要使用异步调用

    生成报告这里比较有趣,确实他是一个和逻辑息息相关的操作,但是通过分析代码,我们可以看出,虽然报告生成是一个重要业务步骤,但是并没有严格到说"如果不能生成报告,就必须回滚上面的操作",并且如果操作失败,在catch中也仅仅是记录了日志,并没有需要尝试重写的逻辑,(很有可能另外的某个程序或者某人,会定时查看日志,发现有错误就重新生成文件)也就是说,就这段代码而言,生成也可以算一个额外逻辑,那么自然也可以去异步操作.可是:千万注意!!

    由于生成报告需要的时间较长,那么生成报告的子线程会长时间运行,长期无法返回线程池,如果请求量太大,频率太快,那就会耗尽线程资源了.

    平心而论,这个问题其实不是异步造成的,即使时同步调用,执行此操作也需要化肥很长时间,调用量太大,频率太快,也会造成排队.而且由于返回时间太长,用户体验也不会好,所以我们的这个ASP.NET多线程的改造应该是有益的。

  • 相关阅读:
    EFCore数据库迁移命令
    EF基本操作
    EF执行存储过程
    [vue]element-ui使用
    [vue]vue-router的使用
    [vue]使用webpack打包
    [vue]插槽与自定义事件
    [vue]计算属性
    [vue]axios异步通信
    [vue]组件
  • 原文地址:https://www.cnblogs.com/ghw0501/p/4733851.html
Copyright © 2011-2022 走看看