你应该知道的 asp.net webform之异步页面

2024-03-17 06:48

本文主要是介绍你应该知道的 asp.net webform之异步页面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于搞asp.net的程序员,都知道所有的服务请求最终都会有一个IhttpHandler来处理,就像我们最常用的aspx页面。相对于IHttpHandler,asp.net还提供了一个异步的相同版本的处理程序接口,它就是IHttpAsyncHandler,同样asp.net也可以让我们的aspx页面实现IHttpAsyncHandler,而不仅仅是IHttpHandler。

 

为什么要异步页面

      我们都知道asp.net维护一个处理页面请求的线程池,每一个新的请求,asp.net就会从其中取出一个空闲的线程来实例化页面,运行处理代码然后呈现HTML,然后返回线程池,等待下一次被激活。但是如果请求到来的过于频繁,比我们线程处理页面返回时间还短,那么这个请求就会被放到一个队列里,如果队列满了,就会产生一个503的服务不可用来拒绝其它的请求。

      可以想象,如果我们的页面在等待一个慢的服务器在处理大量的数据、读取远程文件或一个WEB服务返回数据,这时我们页面没有代码要执行,但是这个线程会被挂起,这就会严重的消耗可用线程,影响网站并发。

      而通过异步页面, 我们可以把这些耗时的处理迁移到其它线程池,而这些异步工作完成时,asp.net会接到通知,再次从线程池激活一个可用线程,处理余下的工作,最终呈现HTML。

 

创建异步页面

      创建异步页面,远比我们想象简单的多,我们首先要在Page指令加一个Async的特性,并把它设为true.

1
<%@ Page Async= "true" AsyncTimeout= "60" ...

还有一个timeout的特性用来指定异步的超时时间,单位是s,默认是45s。

 

      接下来,我们需要调用AddOnPreRenderCompleteAsync注册异步处理:

1
2
3
4
protected void Page_Load( object sender, EventArgs e)
{
     AddOnPreRenderCompleteAsync( new BeginEventHandler(BeginHandler), new EndEventHandler(EndHandler));
}

 

AddOnPreRenderCompleteAsync还提供另一个重载的版本

1
2
3
4
5
public void AddOnPreRenderCompleteAsync(
     BeginEventHandler beginHandler,
     EndEventHandler endHandler,
     Object state
)

首先,开始启动异步任务的委托和处理异步结束时的回调是不可少的,另一个参数,让我们可以传递一些状态的信息给异步开始的方法。

 

异步页面的执行

       在我们展示BeginHandler、EndHandler之前,让我们通过下面转载自MSDN的一张图,看一下异步处理是如何工作的:

 

      我们可以看出我们注册的BeginHandler在prePrend之后才开始执行,这时线程已经回到线程池,代码的处理交到了BeginHandler,我们必须在这里开始一个异步的处理,处理完后返回IAsyncResult的结果,随后EndHandler被调用,之后,线程池的另一个线程被激活,接着处理页面流程。

 

有效的异步处理

      到了这里,你可能感觉到异步页面分明就是一个坑啊,到了最后还是要我们自己去实现异步处理一个耗时的操作。

     但是这可能对于我们来说算不上什么啊,我们有很多种方法开始异步的处理啊,ThreadPool.QueueUserWorkItem,Thread类创建一个专用线程、委托的BeginInvoke和类库中内建的异步支持,如Command的BeginExecuteReader,但是我们能选择的却不是那么多。

 

      第一类,委托的BeginInvoke和ThreadPool.QueueUserWorkItem,这两个会从asp.net请求线程池中激活线程来处理,这就是相同于释放一个线程的同时又从线程池拿一个线程出来,这不是脱裤子放屁吗?一点也起不到增强网站并发处理的能力,还无谓的增加了线程调度的浪费。

 

      第二类,Thread类创建专用线程,这样做可以达到目的,并且可以做到服务器不能处理的工作,但这是非常危险的。如果这样的请求过于和频繁,创建出过多的这样的线程,这对服务器是一种压力,很可能导致服务器再也不能处理其它的请求了。当然,你可以实现一个自定义的线程池来管理这些线程,让他保持在一个合适的范围,并且总是有可用的线程可用,但是这个开发代价就太大了。

 

      接下来就只有.net内置如数据Command的BeginExecuteReader、IO的BeginRead和BeginWriter等处理异步的支持了,其实这也是我们最应该也最值得用的异步方式。让.net去管理线程的问题,又不会从当前请求线程池中拿线程,使用起来也简单强大。

 

异步的实现

      接着上面的代码,我们贴出BeginHandler、EndHandler代码,只是提供一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private SqlConnection con;
private SqlCommand cmd;
private IAsyncResult BeginHandler(Object obj, EventArgs args, AsyncCallback cb, Object state)
{
     string conStr = "" ;
     con = new SqlConnection(conStr);
     cmd = new SqlCommand( "select * from ..." , con);
     con.Open();
     return cmd.BeginExecuteReader(cb, state);
}
private void EndHandler(IAsyncResult ar)
{
     try
     {
         SqlDataReader reader = cmd.EndExecuteReader(ar);
         ……………
     }
     catch (Exception ex)
     {
         //  错误处理
     }
}

 

      这样就实现了一个简单的异步页面的模型,对于这些耗时的操作,我们可能会使用到缓存,这样我们自定义一个实现了IAsyncResult的类,包含我们要使用的数据,在BeginHandler里判断缓存是否存在,如果存在返回自定义实例,并用缓存填充这个实例,不存在就执行异步操作;而在EndHandler里区分出返回实例,使用数据再更新缓存。

 

多异步任务

     如果要处理多个Web服务或者同时去等待web服务,还有数据库操作等等,这时,我们怎么做?

 

1,我们可以调用多次AddOnPreRenderCompleteAsync,每次传入对应的begin和end的委托,但是注册的多个任务是顺序执行的,也就是只有处理完第一个任务end执行过后,才会开始执行第二个任务。

 

2,我们只调用一次AddOnPreRenderCompleteAsync,在begin里启动多少异步操作,但是这个操作会有太多的局限性,并且会更复杂。

 

3,不出大家意外,asp.net提供了处理这样的方法。就是如下的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PageAsyncTask taska = new PageAsyncTask(
     new BeginEventHandler(BeginHandler1),
     new EndEventHandler(EndHandler1),
     null ,
     null
     );
Page.RegisterAsyncTask(taska);
PageAsyncTask taskb = new PageAsyncTask(
     new BeginEventHandler(BeginHandler2),
     new EndEventHandler(EndHandler2),
     null ,
     null
     );
Page.RegisterAsyncTask(taskb);

这样的注册异步任务会同时执行,当所有的异步都执行完毕,才会开始余下的页面的流程。

 

最后我们看一下PageAsyncTask的重载版本:

1
2
3
4
5
6
7
public PageAsyncTask (
     BeginEventHandler beginHandler,
     EndEventHandler endHandler,
     EndEventHandler timeoutHandler,
     Object state,
     bool executeInParallel
)

除了前两个任务开始和结束调用操作参数之外,还提供了一个超时时的处理程序、一个球表示任务状态的对象和一个是否要和其它任务同时执行的布尔值。

 

最后

没有最好,只有最适合,任何一种的处理方式都不会是完美的,就像Jeffrey大师在异步操作中所说的:应尽可能限制线程的使用。异步页面虽然可以让我们网站可以处理更多的请求,但是它并不会让你的用户感觉到页面的呈现变快,甚至会慢些,因为创建线程本身就会产生一定的消耗,并且线程之间的切换开销也相当大。切记。


这篇关于你应该知道的 asp.net webform之异步页面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/818153

相关文章

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

springboot的调度服务与异步服务使用详解

《springboot的调度服务与异步服务使用详解》本文主要介绍了Java的ScheduledExecutorService接口和SpringBoot中如何使用调度线程池,包括核心参数、创建方式、自定... 目录1.调度服务1.1.JDK之ScheduledExecutorService1.2.spring

异步线程traceId如何实现传递

《异步线程traceId如何实现传递》文章介绍了如何在异步请求中传递traceId,通过重写ThreadPoolTaskExecutor的方法和实现TaskDecorator接口来增强线程池,确保异步... 目录前言重写ThreadPoolTaskExecutor中方法线程池增强总结前言在日常问题排查中,

微服务架构之使用RabbitMQ进行异步处理方式

《微服务架构之使用RabbitMQ进行异步处理方式》本文介绍了RabbitMQ的基本概念、异步调用处理逻辑、RabbitMQ的基本使用方法以及在SpringBoot项目中使用RabbitMQ解决高并发... 目录一.什么是RabbitMQ?二.异步调用处理逻辑:三.RabbitMQ的基本使用1.安装2.架构

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery