ASP.NET非同步請求處理(Asynchronous HTTP Handlers)

來源:互聯網
上載者:User

ASP.NET中你可以通過繼承IHttpHandler這個介面來實現一個同步(Synchronous)處理使用者請求的類。比如你希望對於一切類型為fakephp的請求都通過你的Http Hanlder來處理,你可以實現以下這個類:

using System;
using System.Web;

public class FakePHPHttpHandler : IHttpHandler {
  public void ProcessRequest(HttpContext context) {
    //let's pretend we can handle PHP stuff
  }

  public bool IsReusable {
    get { return true; }
  }
}

然後通過在IIS裡將你的dll註冊為.fakephp的handler就可以了。這些在以下的MSDN文檔裡都有介紹:

http://msdn2.microsoft.com/en-us/library/system.web.ihttphandler.aspx

這裡想說的是如何?一個非同步(Asynchronous)d的HTTP Handler。說起來其實也簡單,只要實現IHttpAsyncHandler這個介面就好了。

IHttpAsyncHandler有兩個method:

 BeginProcessRequest
Initiates an asynchronous call to the HTTP handler.

 EndProcessRequest
Provides an asynchronous process End method when the process ends.

這顯然是和.NET Framework中標準的Asynchronous Programming Model (或者叫“非同步模式”, Asynchronous Pattern)是一致的:

參考: Asynchronous Programming Overview

非同步模式的優勢是ASP.NET的worker thread不會等待BeginProcessRequest返回而是會迴轉去接收其他的使用者請求(當然你也可以要求worker thread等待,不過這樣就等於變成了Synchronous Handler)。因為通常處理一個web request的後台時間需要比較長。假設你每秒只能處理10個使用者請求,在同步模式下如果有11個人同時訪問你的服務,就有一個人會看到500 Internal Server Error之類的錯誤訊息了。但如果是非同步模式,worker thread只要調用BeginProcessRequest,而根據Asynchronous Programming Overview,BeginProcessRequest應該立刻返回(“立刻”的含義是它不應該進行長時間的操作,而應該調用QueueUserWorkItem之類的API將耗時的任務放到新線程裡執行),這樣worker thread就可以騰出手去接收下一個user request了。

註:ASP.NET的max worker thread上限可以通過processModel configuration element裡的maxWorkerThreads屬性來改變(參考:Improving ASP.NET Performance 以及 processModel element),但最大的值也只是100 (range from 5 to 100, default 20)。

由此引出的問題自然是:當非同步作業完成時, ASP.NET是如何知道並做相應處理的。這有一下幾種選擇:

1) 當調用BeginProcessRequest的時候,ASP.NET可以同時傳入一個AsyncCallback的delegate,而在你完成非同步作業後,你應該調用這個回呼函數來通知ASP.NET。

2) ASP.NET可以不停地查看IAsyncResult (這個是BeginProcessRequest的傳回值)IsCompleted屬性來確認非同步作業是否已經完成了,當然,當你完成非同步作業時,你有義務將IsCompleted設成true。

3) ASP.NET也可以等待AsyncWaitHandle的訊號,AsyncWaitHandle是IAsyncResult的另一個屬性,這個和經典的Win32裡waiting on kernel object是類似的。

4) ASP.NET可以直接調用EndProcessRequest。

注意:3) 和 4) 是Asynchronous Programming Overview裡規定的標準的blocking execution的方式,也就是說,如果你的主線程在非同步作業完成前無法再做任何工作時,它可以通過3) 或者 4)來等待非同步作業的完成。

從理論上來說,你應該保證你的IHttpAsyncHandler能滿足以上所有4種方式。但現實中,你未必一定如此做。那麼哪些是我們必須實現以匹配ASP.NET的要求的呢?或者ASP.NET究竟是如何?非同步呼叫及返回的呢?

事實上,ASP.NET採用了方法1,也就是說,在調用BeignProcessRequest的時候,ASP.NET傳入了一個AsyncCallback,而你應該在完成非同步作業後調用這個callback,而在這個AsyncCallback裡,ASP.NET又調用了你的EndProcessRequest來做收尾工作。

根據上面的討論,我們可以如下設計我們的Asynchronous Http Hanlder:

public class AsyncFakePHPHttpHandler : IHttpAsyncHandler
{
        private void ProcessRequestCallback(object state)
        {
            AsyncResult async = (AsyncResult)state;
            // this is where the real work is done
            ProcessRequest(async.context);
            async.isCompleted = true;
            if (null != async.asyncCallback)
                async.asyncCallback(async);
        }
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback asyncCallback, object state)
        {
            AsyncResult async = new AsyncResult(context, asyncCallback, state);
            // if the callback is null, we can return immediately and let EndProcessRequest do all the job
            // if callback is not null, we will use our thread pool to execute the necessary asynchronous operations
            // what happens in ASP.NET is that the callback in NOT null, so QueueUserWorkItem will be used
            if (null != async.asyncCallback)
                threadPool.QueueUserWorkItem(ProcessRequestCallback, async);
            return async;
        }
        // this design also satisfies method 4), we implement it this way to follow the Asynchronous Pattern as much as we can
        public void EndProcessRequest(IAsyncResult result)
        {
            AsyncResult async = (AsyncResult)result;
            if (null == async.asyncCallback)
                ProcessRequest(async.context);
        }

總結一下實現非同步Http Handler的要點:

1) 所有在BeginProcessRequest中的耗時操作(比如IO什麼的)都應該採用非同步呼叫(比如BeginRead/EndRead)或者產生新的線程去執行。不錯,你可以設計一個blocking BeginProcessRequest,沒有人能阻止你這麼做。But that's a BAD BAD idea.

2) 實現BeginProcessRequest/EndProcessRequest的目的是允許ASP.NET來非同步呼叫你的Http Handler

3) 你應該建立一個實現IAsyncResult介面的類,在BeginProcessRequest中你會產生一個該類的執行個體並返回給ASP.NET(注意BeginProcessRequest的傳回值類型)。而根據Asynchronous Pattern,ASP.NET在調用EndProcessRequest的時候會把這個執行個體再傳回給你,你可以用這個執行個體來判斷你所執行的任務的目前狀態。

4) 我個人感覺比較容易導致困惑的是這裡“兩段式”的非同步呼叫操作。首先ASP.NET是通過BeginProcessRequest/EndProcessRequest來非同步呼叫我們的Http Handler的。然後我們在BeginProcessRequest又再次用非同步模式(用QueueUserWorkItem或者其他的Begin*/End*操作)去完成真正的工作。實際上第二步的非同步呼叫才是真正產生另一個thread來處理工作的地方。ASP.NET調用我們的BeginProcessRequest只是一種形式上的協議通知,因為是我們告訴ASP.NET:Hey,我是一個非同步handler。ASP.NET說:那好吧,既然你這麼說的,我就用你非同步介面來調用你。事實上,在HttpRuntime的原始碼中,可以看到ASP.NET的操作如下:

                if (app is IHttpAsyncHandler) {
                    // asynchronous handler
                    IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
                    context.AsyncAppHandler = asyncHandler;
                    asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
                }
                else {
                    // synchronous handler
                    app.ProcessRequest(context);
                    FinishRequest(context.WorkerRequest, context, null);
                }

====================================================================

最後的題外話,關於IIS/ASP.NET處理請求的工作流程也是一個很有趣的問題,下面的這篇文章很棒(but the author's English writing kinda sucks, : ) )。比如,從中我們可以知道,整個流程中其實牽涉了兩個Queue,一個是Kernel mode下的,一個是User mode下的,而後者就是ASP.NET所使用的Application Queue,而ASP.NET的worker thread就是從這個Queue裡去取下一個需要處理的請求的。

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/blackvii/archive/2008/01/05/2026903.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.