当接收到一个页面请求时,ASP.NET 会从一个线程池中获取一个线程,并将页面请求分配给该线程。一个普通的,或者说是同步的页面在请求期间会占用线程,以防止线程被用于处理其他请求。如果同步请求变为 I/O 密集状态,例如,当该请求调用一个远程 Web 服务或查询远程数据库并等待调用返回时,则分配给它的线程在调用返回前会始终处于闲置状态。这种情况会限制可伸缩性,因为线程池中的可用线程是有限的。如果处理请求的所有线程都因等待 I/O 操作的完成而阻塞,则会有多余的请求排队等待这些线程的释放。最好的情况是出现吞吐量降低,因为需要等待更长的等待才能处理请求。最糟糕的情况是队列被填满而 ASP.NET 无法处理后续请求,并提示 503“服务器不可用”错误。
异步页面的出现为解决 I/O 密集型的请求所导致的此类问题提供了简洁的方案。页面处理要在线程池中的一个线程上进行,但是当一个异步 I/O 操作响应来自 ASP.NET 的信号并开始进行时,该线程会返回原先的线程池。操作完成后,ASP.NET 会从线程池中获取另一个线程来完成处理请求。这样,线程池的线程使用率得到提高,可伸缩性也因此得以增强。那些本来要等待 I/O 操作完成而阻塞的线程此时可以用于处理其他请求。这样做的直接好处就是避免请求执行冗长的 I/O 操作,因此可以快速进出管道。等待进入管道的时间过长会对此类请求的执行造成的很大的负面影响。
以上文字摘自:http://msdn.microsoft.com/msdnmag/issues/05/10/WickedCode/Default.aspx?loc=zh#S1
下面是一个具体异步调用的示例。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Async.aspx.cs" Inherits="Async" Async="true" ValidateRequest="false" EnableEventValidation="false" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAnsyc" runat="server" Text="Ansyc" OnClick="btnAnsyc_Click" />
<asp:Label ID="lblResponse" runat="server" Text=""></asp:Label>
</div>
</form>
</body>
</html>
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
public partial class Async : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnAnsyc_Click(object sender, EventArgs e)
{
Page.AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginRequest), new EndEventHandler(EndRequest));
}
IAsyncResult BeginRequest(object sender, EventArgs e, AsyncCallback _callback, object state)
{
_request = WebRequest.Create("http://www.baidu.com/index.html");
return _request.BeginGetResponse(_callback, state);
}
void EndRequest(IAsyncResult _res)
{
string text;
using (WebResponse _Response = _request.EndGetResponse(_res))
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(_Response.GetResponseStream(), System.Text.Encoding.Default))
{
text = reader.ReadToEnd();
}
}
lblResponse.Text = text;
}
WebRequest _request;
}