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服务器端多线程设计——异步Web服务

ASP.NET服务器端多线程设计——异步IHttpHandler

 

对 JAVA 开发有兴趣的朋友欢迎加入QQ群:174850571 共同探讨!
对 .NET  开发有兴趣的朋友欢迎加入QQ群:162338858 共同探讨 !

posted on 2011-01-14 14:34  风尘浪子  阅读(3012)  评论(6编辑  收藏  举报

导航