你应该知道的 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

相关文章

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

在ASP.NET项目中如何使用C#生成二维码

《在ASP.NET项目中如何使用C#生成二维码》二维码(QRCode)已广泛应用于网址分享,支付链接等场景,本文将以ASP.NET为示例,演示如何实现输入文本/URL,生成二维码,在线显示与下载的完整... 目录创建前端页面(Index.cshtml)后端二维码生成逻辑(Index.cshtml.cs)总结

C#异步编程ConfigureAwait的使用小结

《C#异步编程ConfigureAwait的使用小结》本文介绍了异步编程在GUI和服务器端应用的优势,详细的介绍了async和await的关键作用,通过实例解析了在UI线程正确使用await.Conf... 异步编程是并发的一种形式,它有两大好处:对于面向终端用户的GUI程序,提高了响应能力对于服务器端应

解决hive启动时java.net.ConnectException:拒绝连接的问题

《解决hive启动时java.net.ConnectException:拒绝连接的问题》Hadoop集群连接被拒,需检查集群是否启动、关闭防火墙/SELinux、确认安全模式退出,若问题仍存,查看日志... 目录错误发生原因解决方式1.关闭防火墙2.关闭selinux3.启动集群4.检查集群是否正常启动5.

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

如何在Java Spring实现异步执行(详细篇)

《如何在JavaSpring实现异步执行(详细篇)》Spring框架通过@Async、Executor等实现异步执行,提升系统性能与响应速度,支持自定义线程池管理并发,本文给大家介绍如何在Sprin... 目录前言1. 使用 @Async 实现异步执行1.1 启用异步执行支持1.2 创建异步方法1.3 调用

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文