充分發(fā)揮異步在 ASP.NET 中的強(qiáng)大優(yōu)勢(shì)

作者:Brij Bhushan Mishra

最近幾年治唤,異步編程受到極大關(guān)注棒动,主要是出于兩個(gè)關(guān)鍵原因:首先,它有助于提供更好的用戶體驗(yàn)宾添,因?yàn)椴粫?huì)阻塞 UI 線程船惨,避免了處理結(jié)束前出現(xiàn) UI 界面掛起。其次辞槐,它有助于大幅擴(kuò)展系統(tǒng)掷漱,而且無需添加額外硬件。

但是榄檬,編寫合適的異步代碼來管理線程本身是項(xiàng)乏味的工作卜范。雖然如此,其巨大好處讓許多新舊技術(shù)紛紛開始使用異步編程鹿榜。微軟自發(fā)布了 .NET 4.0以后也對(duì)其投入頗多海雪,隨后在 .NET 4.5中引入了 async 和 await 關(guān)鍵字,使異步編程變得前所未有地簡(jiǎn)單舱殿。

但是奥裸,ASP.NET 中的異步功能自一開始就可以使用,只是從來沒有得到應(yīng)有的重視沪袭。而且湾宙,考慮到 ASP.NET 和 IIS 處理請(qǐng)求的方式,異步體現(xiàn)的優(yōu)勢(shì)可能更明顯。通過異步侠鳄,我們很容易就可以大幅提高 ASP.NET 應(yīng)用程序的擴(kuò)展性埠啃。隨著新的編程結(jié)構(gòu)引入,如 async 和 await 關(guān)鍵字伟恶,我們也應(yīng)該學(xué)會(huì)使用異步編程的強(qiáng)大功能碴开。

在本篇博文中,我們將討論一下 IIS 和 ASP.NET 處理請(qǐng)求的方式博秫,然后看看 ASP.NET 中哪些地方可以使用異步潦牛,最后再討論幾個(gè)最能體現(xiàn)異步優(yōu)勢(shì)的場(chǎng)景。

請(qǐng)求是如何處理的?

每個(gè) ASP.NET 請(qǐng)求都要先通過 IIS挡育,然后再由 ASP.NET 處理程序進(jìn)行最終處理巴碗。 首先IIS 接收請(qǐng)求,初步處理后静盅,發(fā)送給ASP.NET(必須是一個(gè)ASP.NET請(qǐng)求)良价,然后由ASP.NET進(jìn)行實(shí)際處理并生成響應(yīng),之后該響應(yīng)通過IIS發(fā)回給客戶蒿叠。在IIS上明垢,有一些工作進(jìn)程負(fù)責(zé)從隊(duì)列中取出請(qǐng)求,并執(zhí)行IIS 模塊市咽,然后再將該請(qǐng)求發(fā)送到ASP.NET 隊(duì)列痊银。但是,ASP.NET本身不創(chuàng)建任何線程施绎,也沒有處理請(qǐng)求的線程池溯革,而是通過使用CLR 線程池,從中獲取線程來處理請(qǐng)求谷醉。因此致稀,IIS 模塊調(diào)用ThreadPool.QueueUserWorkItem,將請(qǐng)求排入隊(duì)列俱尼,供CLR 工作線程處理抖单。我們都知道,CLR線程池是由CLR管理遇八,并且能夠自動(dòng)調(diào)整(也就是說矛绘,它根據(jù)需要?jiǎng)?chuàng)建和銷毀進(jìn)程)。這里還要記住刃永,創(chuàng)建和銷毀線程是項(xiàng)很繁重的任務(wù)货矮,這就是為什么CLR線程池允許使用同一個(gè)線程處理多個(gè)任務(wù)。下面來看一個(gè)描述請(qǐng)求處理過程的圖示斯够。

在上圖中可以看到囚玫,請(qǐng)求首先由 HTTP.sys接收喧锦,并添加到相應(yīng)內(nèi)核級(jí)應(yīng)用程序池隊(duì)列。然后劫灶,一個(gè)IIS工作線程從隊(duì)列中取出請(qǐng)求裸违,處理后將其傳到ASP.NET 隊(duì)列。注意本昏,該請(qǐng)求如果不是一個(gè)ASP.NET請(qǐng)求,將從 IIS 自動(dòng)返回枪汪。最后涌穆,從CLR線程池中分配一個(gè)線程,負(fù)責(zé)處理該請(qǐng)求雀久。

ASP.NET中異步的使用場(chǎng)景是宿稀?

所有請(qǐng)求大致可以分為兩類:

  1. CPU Bound 類
  2. I/O Bound 類

CPU Bound 類請(qǐng)求,需要 CPU 時(shí)間赖捌,而且是在同一進(jìn)程中執(zhí)行祝沸;而 I/O Bound 類請(qǐng)求,本身具有阻塞性越庇,需要依賴其他模塊執(zhí)行 I/O 操作并返回響應(yīng)罩锐。阻塞性請(qǐng)求是提高應(yīng)用程序可伸縮性的主要障礙,而且大多數(shù)web應(yīng)用程序中卤唉,在等待 I/O 操作的過程中浪費(fèi)了大量時(shí)間涩惑。 因此以下場(chǎng)景適合使用異步:

  1. I/O Bound 類請(qǐng)求,包括:

    a. 數(shù)據(jù)庫(kù)訪問

    b. 讀/寫文件

    c. Web 服務(wù)調(diào)用

    d. 訪問網(wǎng)絡(luò)資源

  2. 事件驅(qū)動(dòng)的請(qǐng)求桑驱,比如SignalR

  3. 需要從多個(gè)數(shù)據(jù)源獲取數(shù)據(jù)的場(chǎng)景

作為示例竭恬,這里創(chuàng)建一個(gè)簡(jiǎn)單的同步頁面,然后再將它轉(zhuǎn)換成異步頁面熬的。 本示例設(shè)置了1000ms的延遲(以模擬一些繁重的數(shù)據(jù)庫(kù)或web服務(wù)調(diào)用等)痊硕,而且還使用WebClient下載了一個(gè)頁面,如下所示:

    protected void Page_Load(object sender, EventArgs e)

    {

        System.Threading.Thread.Sleep(1000);

        WebClient client = new WebClient();

        string downloadedContent = client.DownloadString("https://msdn.microsoft.com/en-us/library/hh873175%28v=vs.110%29.aspx");

        dvcontainer.InnerHtml = downloadedContent;

    }

現(xiàn)在將該頁面轉(zhuǎn)換成異步頁面押框,這里主要涉及三個(gè)步驟:

  1. 在頁面指令中添加Async = true岔绸,將該頁面轉(zhuǎn)換成異步頁面,如下所示:

     <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Home.aspx.cs" Inherits="AsyncTest.Home" Async="true" AsyncTimeout="3000" %>
    

這里還添加了 AsyncTimeout (可選項(xiàng))强戴,請(qǐng)根據(jù)需求選擇亭螟。

2.將此方法轉(zhuǎn)換成異步方法。在這里把Thread.Sleep 與 client.DownloadString 轉(zhuǎn)換成異步方法如下所示:

    private async Task AsyncWork()

    {

        await Task.Delay(1000);

        WebClient client = new WebClient();

        string downloadedContent = await client.DownloadStringTaskAsync("https://msdn.microsoft.com/en-us/library/hh873175%28v=vs.110%29.aspx ");

        dvcontainer.InnerHtml = downloadedContent;
 
    }

3.現(xiàn)在可以直接在 Page_Load (頁面加載)上調(diào)用此方法骑歹,使其異步预烙,如下所示:

    protected async void Page_Load(object sender, EventArgs e)

    {
        await AsyncWork();
    }

但是這里的 Page_Load 返回的類型是async void,這種情況無論如何都應(yīng)該避免道媚。我們知道扁掸,Page_Load 是整個(gè)頁面生命周期的一部分翘县,如果我們把它設(shè)置成異步,可能會(huì)出現(xiàn)一些異常情況和事件谴分,比如生命周期已經(jīng)執(zhí)行完畢而頁面加載仍在運(yùn)行锈麸。 因此,強(qiáng)烈建議大家使用 RegisterAsyncTask 方法注冊(cè)異步任務(wù)牺蹄,這些異步任務(wù)會(huì)在生命周期的恰當(dāng)時(shí)間執(zhí)行忘伞,可以避免出現(xiàn)任何問題。

    protected void Page_Load(object sender, EventArgs e)
    {
        RegisterAsyncTask(new PageAsyncTask(AsyncWork));
    } 

現(xiàn)在沙兰,頁面已經(jīng)轉(zhuǎn)換成了異步頁氓奈,它就不再是一個(gè)阻塞性請(qǐng)求。

筆者在 IIS8.5 上部署了同步頁面和異步頁面鼎天,并使用突發(fā)負(fù)載對(duì)兩者進(jìn)行了測(cè)試舀奶。測(cè)試結(jié)果發(fā)現(xiàn),相同的機(jī)器配置斋射,同步頁面在2-3秒內(nèi)只能提取1000個(gè)請(qǐng)求育勺,而異步頁面能夠?yàn)?200多個(gè)請(qǐng)求提供服務(wù)。此后罗岖,開始收到超時(shí)(Timeout)或服務(wù)器不可用(Server Not Available)的錯(cuò)誤涧至。雖然兩者的平均請(qǐng)求處理時(shí)間沒有多大差別,但是通過異步頁面呀闻,可以處理兩倍以上的請(qǐng)求化借。這足以證明異步編程功能強(qiáng)大,所以應(yīng)該充分利用它的優(yōu)勢(shì)捡多。

ASP.NET中還有幾個(gè)地方也可以引入異步:

  1. 編寫異步模塊
  2. 使用IHttpAsyncHandler 或 HttpTaskAsyncHandler 編寫異步HTTP處理程序
  3. 使用web sockets 或 SignalR

結(jié)論

本篇博文中,我們討論了異步編程蓖康,而且發(fā)現(xiàn),新推出的async 和 await關(guān)鍵字垒手,使異步編程變得十分簡(jiǎn)單蒜焊。我們討論的話題包括 IIS和ASP.NET如何處理請(qǐng)求,以及在哪些場(chǎng)景中異步的作用最明顯科贬。另外泳梆,我們還創(chuàng)建了一個(gè)簡(jiǎn)單示例,討論了異步頁面的優(yōu)勢(shì)榜掌。最后我們還補(bǔ)充了幾個(gè)ASP.NET中可以使用異步的地方优妙。

本文系 OneAPM 工程師編譯呈現(xiàn)。OneAPM 能助您輕松鎖定 .NET 應(yīng)用性能瓶頸憎账,通過強(qiáng)大的 Trace 記錄逐層分析套硼,直至鎖定行級(jí)問題代碼。以用戶角度展示系統(tǒng)響應(yīng)速度胞皱,以地域和瀏覽器維度統(tǒng)計(jì)用戶使用情況邪意。想閱讀更多技術(shù)文章九妈,請(qǐng)?jiān)L問 OneAPM 官方博客

原文地址:http://www.infragistics.com/community/blogs/brijmishra/archive/2015/10/28/leveraging-the-power-of-asynchrony-in-asp-net.aspx

本文轉(zhuǎn)自 OneAPM 官方博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雾鬼,一起剝皮案震驚了整個(gè)濱河市萌朱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌策菜,老刑警劉巖晶疼,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異又憨,居然都是意外死亡冒晰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凌摄,你說我怎么就攤上這事需频。” “怎么了埠况?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵耸携,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我辕翰,道長(zhǎng)夺衍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任喜命,我火速辦了婚禮沟沙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壁榕。我一直安慰自己矛紫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布牌里。 她就那樣靜靜地躺著颊咬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牡辽。 梳的紋絲不亂的頭發(fā)上喳篇,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音态辛,去河邊找鬼麸澜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛因妙,可吹牛的內(nèi)容都是我干的痰憎。 我是一名探鬼主播票髓,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铣耘!你這毒婦竟也來了洽沟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蜗细,失蹤者是張志新(化名)和其女友劉穎裆操,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炉媒,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踪区,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吊骤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缎岗。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖白粉,靈堂內(nèi)的尸體忽然破棺而出传泊,到底是詐尸還是另有隱情,我是刑警寧澤鸭巴,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布眷细,位于F島的核電站,受9級(jí)特大地震影響鹃祖,放射性物質(zhì)發(fā)生泄漏溪椎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一恬口、第九天 我趴在偏房一處隱蔽的房頂上張望校读。 院中可真熱鬧,春花似錦楷兽、人聲如沸地熄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽端考。三九已至,卻和暖如春揭厚,著一層夾襖步出監(jiān)牢的瞬間却特,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工筛圆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裂明,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓太援,卻偏偏與公主長(zhǎng)得像闽晦,于是被迫代替她去往敵國(guó)和親扳碍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容