ASP.NET服务器端多线程设计——异步IHttpHandler
在.NET系统中,可以通过Thread直接创建线程。但为了避免使用过多的线程对系统性能做成影响,微软特别开发了一个ThreadPool(CLR线程池)对线程进行管理。
ThreadPool.QueueUserWorkItem(new WaitCallback(method), objcet);//新建线程
CLR线程池的线程却分成两种:工作者线程与IO线程
ThreadPool.GetAvailableThreads(out int a1, out int a2);//a1为工作者线程,a2为IO线程
一般ASP.NET的页面请求会在工作者线程中运行,但当使用硬盘文件读取,外部数据交换时就可以使用IO线程来降低工作者线程的压力。(注意:如果读取小型文件时异步使用IO线程,工作效率可能比单线程操作还要低,建议阁下参考Jeffrey Richter名著《CLR via C#》 )
当客户端要获取网络文件时,一般会使用IHttpHandler方式,若是文件流量太大时,CLR线程池的工作者线程就被会长期占用并处于等待状态,当线程大于线程池的最大值 (IIS5.0默认值为25*CPU数,IIS 7.0默认值为250*CPU数)的时候,其他请求将处于等待状态,这样会对服务器造成压力。这时候可以通过异步的HttpHanlder利用IO线程对文件进行异步处理。其作用在于及时释放CLR线程池的工作者线程,将读取文件的工作交于异步IO线程。
class File
{
FileStream fileStream;
byte[] bytes;
}
public class Handler : IHttpAsyncHandler {
//异步HttpHandler继承于IHttpAsyncHandler,并包含BeginProcessRequest方法和EndProcessRequest方法
public byte[] bytes;
public HttpContext context1;
public void ProcessRequest(HttpContext context)
{
throw new Exception();
}
public IAsyncResult
BeginProcessRequest (HttpContext context,AsyncCallback callback,object o)
{
context1 = context;
//使用异步I/O线程时注意用下面方式建立FileStream对象,并把最后的参数userAsync设置为true
//若文件大小小于缓冲值1024,那文件将一次性读取,回调时依然会使用CLR线程中池的工作者线程
FileStream fileStream = new FileStream("E://My
Webs/WebService1/TextFile.txt",
FileMode.Open,FileAccess.Read,FileShare.Read, 1024, true
);
bytes = new byte[fileStream.Length];
File file1=new File();
file1.fileStream=fileStream;
file1.bytes=bytes;
return fileStream.BeginRead(file1.bytes, 0, (int)fileStream.Length, callback, file1);
//此时,CLR线程池的工作者线程就会被及时释放,当完成读取时,再度调用IO线程完成操作。
}
public void EndProcessRequest(IAsyncResult result)
{
File file1 = (File)result.AsyncState;
file1.fileStream.EndRead(result);
file1.fileStream.Close();
context1.Response.Write(System.Text.Encoding.UTF8.GetString(file1.bytes));
int n1,n2;
ThreadPool.GetAvailableThreads(out n1, out n2);
context1.Response.Write(String.Formate("WorkerThreads Count is {0}! ”+
“ IOThreads Count is {1} !",n1.ToString(),n2.ToString() ));
//此时检测线程池,输出将会是WorkerThreads Count is 1000! IOThreads Count is 999!
//说明异步方法使用的是IO线程
}
public bool IsReusable {
get {
return false;
}
}
}
在使用WebService时,也可以使用异步调用的方式。
http://www.pin5i.com/showtopic-10763.html
同样对于SQL数据库,Socket,HttpWebRequest...也可使用异步进行访问。
- DNS操作: BeginGetHostByName、BeginResolve。
- Socket操作: BeginAccept、BeginConnect、BeginReceive等等。
- WebRequest操作: BeginGetRequest、BeginGetResponse。
- SqlCommand操作: BeginExecuteReader、 BeginExecuteNonQuery等等。这可能是开发一个Web应用时最常用的异步操作了。如果需要在执行数据库操作时得到IOCP支持,那么需 要在连接字符串中标记Asynchronous Processing为true(默认为false),否则在调用BeginXXX操作时就会抛出异常。
但可惜此方式并不合适使用异步委托 ,当使用异步委托时(BeginInvoke,EndInvoke),系统所新增的线程同样来CLR线程池的工作者线程,如果麻木地使用异步方式,会适得其反,对系统的性能做成影响。
ASP.NET服务器端多线程设计——异步IHttpHandler
对 JAVA 开发有兴趣的朋友欢迎加入QQ群:174850571 共同探讨!
对 .NET 开发有兴趣的朋友欢迎加入QQ群:162338858 共同探讨 !