非同步編程系列第02章 你有什麼理由使用Async非同步編程

来源:http://www.cnblogs.com/tdws/archive/2016/06/26/5618321.html
-Advertisement-
Play Games

寫在前面 在學非同步,有位園友推薦了《async in C#5.0》,沒找到中文版,恰巧也想提高下英文,用我拙劣的英文翻譯一些重要的部分,純屬娛樂,簡單分享,保持學習,謹記謙虛。 如果你覺得這件事兒沒意義翻譯的又差,盡情的踩吧。如果你覺得值得鼓勵,感謝留下你的贊,在今後每一次應該猛烈突破的時候,不選擇 ...


寫在前面

  在學非同步,有位園友推薦了《async in C#5.0》,沒找到中文版,恰巧也想提高下英文,用我拙劣的英文翻譯一些重要的部分,純屬娛樂,簡單分享,保持學習,謹記謙虛。

  如果你覺得這件事兒沒意義翻譯的又差,盡情的踩吧。如果你覺得值得鼓勵,感謝留下你的贊,在今後每一次應該猛烈突破的時候,不選擇知難而退。在每一次應該獨立思考的時候,不選擇隨波逐流,應該全力以赴的時候,不選擇儘力而為,願愛技術的園友們不辜負每一秒存在的意義。

   轉載和爬蟲請註明原文鏈接http://www.cnblogs.com/tdws/p/5618321.html,博客園 蝸牛 2016年6月25日6:15pm。

目錄

第01章 非同步編程介紹

第02章 為什麼使用非同步編程

    桌面應用程式
    打個比方:咖啡館
    Web應用程式服務端代碼
    另一個比方:餐館廚房
    Silverlight, Windows Phone, and Windows 8
    並行代碼
    一個示例

第03章 手動編寫非同步代碼

第04章 編寫非同步方法

第05章 Await究竟做了什麼

第06章 以Task為基礎的非同步模式

第07章 非同步代碼的一些工具

第08章 哪個線程在運行你的代碼

第09章 非同步編程中的異常

第10章 並行使用非同步編程

第11章 單元測試你的非同步代碼

第12章 ASP.NET應用中的非同步編程

第13章 WinRT應用中的非同步編程

第14章 編譯器在底層為你的非同步做了什麼

第15章 非同步代碼的性能

為什麼使用非同步編程

  非同步編程很重要很有用處,原因有很多,主要看你在構建什麼類型的應用程式。其中一部分的用處和益處在任何應用程式中都隨處可見,及時某些類型的應用程式你沒有接觸過。如果這適合你,請閱讀整篇文章,做為背景知識將會幫助你更好的理解整個上下文。

  桌面應用程式

  桌面app有一個主要的性能要求。要求app讓用戶一直感覺到是可響應的。HCI研究表明,緩慢的應用程式不會得到用戶的關註,最好是要有一個進度條提示器。

  當應用程式凍住或者說未響應狀態,用戶會變得沮喪。凍結的原因通常是因為一個耗時操作,或者因為一個緩慢的計算,或者因為IO,或者網路請求。

  你用的C#的桌面UI框架都是單個UI線程的,包括:

·Winforms

·WPF

·Silverlight

  UI線程是唯一的可以控制特性視窗的,也是唯一一個線程來檢查用戶輸入和為他們執行相應工作。如果這個線程很繁忙或者被阻塞數幾十毫秒,用戶就會註意到這個app是緩慢的。

  非同步代碼,甚至手工編寫,意味著UI線程可以返回檢查消息隊列進行對用戶操作的主要工作,並對他們響應。它也可以執行進度動畫,併在最近版本的視窗,滑鼠懸停動畫,這都是重要的視覺線索給用戶,給人一個好印象的響應的應用程式。

   所有常見的用戶界面框架只使用一個線程的原因是為了簡化同步。如果有很多線程的話,當一個線程正在鋪設佈局控制項過程中,另一個線程試圖讀取按鈕的寬度,這樣衝突了。為了避免這樣的事情發生,你需要大量的使用鎖,這將會大大降低程式的性能。

  打個比方:咖啡館

  我想用一個比喻來直觀的幫你把握所涉及的問題。如果你覺得已經理解,那麼請跳過這一小節。

  想象一下,有個小咖啡館為顧客早餐提供麵包,唯一的工作人員就是老闆,他非常註重和關心客戶服務,但是還沒有學會非同步的技術。UI線程模型和咖啡店的老闆很相似,就像在電腦中必須通過線程一樣,咖啡店員工在咖啡館中工作,在這樣的情況下,就像他們只有一個UI線程一樣。

  第一個客戶要一片麵包,老闆將麵包放到烤箱中,然後他在烤麵包的過程中等待著。客戶問老闆在哪能找到黃油,但是老闆把她忽略了,就像他是阻塞型代碼一樣。五分鐘過去,麵包已經烤好並且拿給了客戶。到了這個時候,已經排起了長隊,客戶最討厭的就是等待和被忽略,老闆這樣做一點也不理想。

   現在,我們來教老闆非同步。

  首先要確保他的烤箱可以非同步操作,當我們編寫非同步代碼時,我們要確保耗時操作在執行結束時能夠告訴我們,同樣的,麵包烤箱也需要一個定時器,並且要響亮以便能夠被他註意到。

  另外就是他能夠在烤箱開始的時候忽略它,他應該回去繼續為顧客服務,同樣的,我們的非同步代碼也要在執行耗時操做時返回,這樣UI線程可以繼續相應用戶操作。

  有兩點原因:

·可以更好的響應用戶請求—客戶可以詢問黃油在哪並且不被老闆忽略。

·用戶可以同時開始另一個操作—下一個客戶也可以開始點餐並且讓老闆烹飪。

  咖啡館老闆現在可以同時為多個客戶服務,唯一的限制就是烤箱的數量和拿取麵包的時間。但這樣帶來了一系列問題:老闆發現自己並不能記住哪片麵包是哪個客戶所點,UI線程完全不能記住當他返回時,他在等待的是哪個操作。

  所以我們必須再開始的時候附加一個回調,去提醒我們當他結束時該做什麼。至於咖啡館老闆,很簡單的就是在烤箱上貼上客戶姓名的標簽。但我們可能需要更複雜的東西,一般來說我們希望能夠對耗時工作結束後需要做什麼事情,提供完整說明,一旦完成了工作。

  有了這些,咖啡館老闆現在完全是非同步的了,並且生意紅火。用戶體驗感變得更好。這就是等待很少,更具效應能力。希望這個比方能夠幫助你的直覺來理解為什麼非同步在UI application上如此重要。

  Web應用程式服務端代碼

  ASP.NET的Web伺服器沒有像UI代碼一個線程的的硬限制。這就是說,在web中使用多線程編程依然有很多好處。耗時操作,尤其是遠程資料庫Query,在web app中非常常見。

  取決於你的IIS版本,將會有用於處理web請求的線程總數和併發請求數的限制。如果你的請求花了大量的時間在等待資料庫Query上,那麼增加併發請求數去增加伺服器吞吐量是一個好的方法。

  當一個線程被阻塞,一直在等待,它不占用UPU時間。然而,你不要誤以為這意味著它不占用伺服器資源。事實上,線程占用兩項重要的開銷,即使他們在被阻塞:

·記憶體

   每個托管線程儲備在Windows上的虛擬記憶體的位元組。如果你有幾十個線程是完全沒有問題的,但是當你有上百個線程時很容易就會失控。如果記憶體使用了磁碟上的虛擬記憶體空間,那麼你的線程會變得特別慢。

·調度器的開銷

   操作系統的調度器負責選擇在什麼時間,在哪個CPU上,執行哪個線程。即使當線程被阻塞時,調度器也必須考慮到他們,並且判斷它們是否變得非阻塞(阻塞結束)。這樣減緩了線程上下文切換,甚至可以拖慢整個系統。

  在他們之間,這些開銷負載到到你的伺服器上,增加延遲並且降低吞吐量。

  請記住:非同步編程的主要特征是當線程開始執行一段耗時操作,這個線程會被釋放去做其他一些事情。在ASP.NET代碼下,線程來自於線程池,所以在執行耗時操作期間,線程會被返回到線程池,他可以處理其他請求,以很少的線程就可以來處理同阻塞代碼情況相同的請求數量。//譯者註解,如果你不理解這句話,可以參照我的另一篇文章中的解惑二:文章鏈接

  另一個比方:餐館廚房

  web伺服器和餐館模型很接近,很多客人點餐,廚房會儘可能的快速滿足他們的要求。

  我們的廚房有很多廚師,每個廚師代表一個線程。他們按照用戶的訂單來烹飪,但是在整個準備過程中,每道菜只需要烹飪一會兒,並且廚師可能等待著沒什麼事情做。這反映了web請求處理的方式,通常在執行資料庫Query請求資料庫數據的這段時間,web伺服器並沒有參與。

  在類似於阻塞型的廚房,廚師將會在烹飪工具前等待菜餚的烹飪。精確模擬一個線程,廚師有一個奇怪的合同,廚師在等待烹飪結束的過程中不被支付薪水,因為一個線程不占用CPU時間當他們被阻塞時,也需要他們在這期間讀報紙。

  但即使我們沒有向他們支付,我們依然可以使用新廚師為另一道菜餚,那些等待烹飪結束的廚師依然空閑在廚房。但是,我們不能讓幾十個廚師在廚房工作,這樣連轉身都困難,最終導致每個人的工作效率都很低。

  當然我們用非同步工作方式會更好,每當菜餚正在烤箱中烹飪,廚師記下當前在烹飪的是什麼菜餚,在什麼階段或者階段,然後找到一項新的任務(菜餚)去做。當菜餚烹飪結束,任意一個廚師可以將菜餚拿出來繼續處理。//譯者註釋:記住,每個廚師代表一個線程,試著當作線程來理解,你會明白原理。

   Web伺服器正是這種強大的系統。是需要極少部分線程就可以承受以前的併發量,或者能做到以前在開銷上不可行的事情。事實上,一些web框架,特別是nodejs,拒絕多線程並行的方式,選擇單個線程來非同步處理所有請求。他們可以用單線程來處理比多線程並行更多的請求,但是阻塞,系統可以處理的總數。同樣的,一個組織能力強的廚師在一個空廚房中可以烹飪比,上百個廚師在廚房還多的菜餚,因為出事多了他們花了幾乎所有時間在絆倒彼此和閱讀報紙上。

  Silverlight, Windows Phone, and Windows 8

  暫時不翻譯此部分

  並行代碼

  電腦是多處理核心的,每個核心之間相互獨立。程式需要充分利用多核心的優勢,但由這些程式使用的任何記憶體不能被並行代碼立即同時寫入,否則記憶體容易被損害。

   也許在編程中使用比較純凈的統一的風格是更好的,即不在記憶體中操作狀態,而是操作不變值。這將會讓我們享受並行系統的好處,但這也不適用於某些程式。就像User Interfaces需要狀態,資料庫就是狀態。//譯者註釋:原文的狀態是state,這個詞也許翻譯為狀態不恰當。

  標準的解決方案是使用互斥鎖以防兵行代碼同時訪問相同記憶體。但這又帶來一系列問題,你的代碼通常會帶一把鎖,然後做出一個方法調用或註冊一個事件又帶另一個鎖。通常,同時保持兩個鎖不是必要的,但代碼是沒有人類這樣思想的。

  下麵是一個對於鎖的假設結構,意思是說,總體來講,更多的線程結束,等待鎖,直到他們可以做一些有用的工作。在一些情況下,兩個線程同時等待另一個線程保持的鎖,引發了死鎖。這些錯誤是很難預測,很難重現,而且往往很難修複。

  最有前景的解決方案之一是Actor模型計算。這是一個在每塊可寫的記憶體只能存在於一個Actor內的設計。唯一的方式來使用這塊記憶體是向Actor發送消息,從而一次處理一個,並且可能會得到另一條回覆消息。這就是非同步編程。詢問Actor的操作是一種典型的非同步操作,因為我們可以繼續做其他事情直到回覆消息抵達。這意味著你可以使用非同步來做,詳細將會見第10章.

  一個示例

  我們將會看到一個desktop UI app,它急需轉換為非同步風格。源代碼地址https://bitbucket.org/alexdavies74/faviconbrowser .我建議你如果可以的話跟隨著來進行,在VS中打開。

  運行程式,你會看到一個視窗有一個按鈕。如果你按這個按鈕,它會顯示一些流行的網站的圖標。它通過下載大多數網站包含的一個文件名為favicon.ico(圖2-1)。

************************配圖 downloads the favicon and adds it to a WPF WrapPanel in the window.

   讓我們看一看代碼。重要的方法是下載的圖標,並將其添加到視窗中的WPF wrappanel。

private void AddAFavicon(string domain)
{
WebClient webClient = new WebClient();
byte[] bytes = webClient.DownloadData("http://" + domain + "/favicon.ico");
Image imageControl = MakeImageControl(bytes);
m_WrapPanel.Children.Add(imageControl);
}

  你將會註意到代碼但全是同步的,線程在下載的過程中是阻塞的。你可能還會註意到點擊按鈕的時候,視窗有幾秒變成了未響應的狀態。和你知道的一樣,這是因為在下載小圖標icons時UI線程阻塞,並且不能返回處理用戶的操作。

  我們將使用這個例子在接下來的章節,並將其轉化為非同步編程的程式。

寫在最後

  早上九點多開始,除了吃飯,健身,基本一直在翻譯和學習第二章。我覺得對於ASP.NET非同步編程,廚房這個這個比方簡直太棒太恰當了!如果你對你有些許益處,不要吝嗇你的贊,給個鼓勵。不准確的地方,也請前輩們不吝賜教,我將虛心改正。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 固定(穩定)執行計劃 你的應用的功能時快時慢,變化比較大,功能的性能能夠保持一種穩定的狀態,ORACLE 固定執行計劃,採用以下這幾種方式 oracle 9i使用 Outline oracle 10g採用 sql profile oracle 11g增加了sql plan manage oracle ...
  • SQL Server T-SQL高級查詢 高級查詢在資料庫中用得是最頻繁的,也是應用最廣泛的。 Ø 基本常用查詢 --select select * from student; --all 查詢所有 select all sex from student; --distinct 過濾重覆 selec ...
  • 以前總結過一遍博文SQL Server刪除distribution資料庫,裡面介紹瞭如何刪除distribution資料庫。今天介紹一個刪除distribution的特殊案例, 在這之前,我不知道這個伺服器上的Replication被如何折騰過,在SSMS管理界面的Local Publication... ...
  • 背水一戰 Windows 10 之 綁定: TemplateBinding 綁定, 與 RelativeSource 綁定, 與 StaticResource 綁定 ...
  • 本寶寶只是一個菜鳥,寫寫學習筆記,以便溫故知新,如果哪裡不對或者不足,望大牛指正。 1.我們先舉個例子說明一下,eg:加減乘除的運算[一步步優化] ⅰ.[第一種寫法] ⅱ.以上的這種寫法,顯得特別不專業,也不美觀,那就優化一下,看看[第二種寫法] ⅲ.以上寫法是不是也有許多不足呢? 業務邏輯層和和客 ...
  • 橋接模式:實現系統可能有多角度分類,每一種分類都有可能的變化,那麼就把這種多角度分離出來讓他們獨立變化,減少它們之間的耦合 下麵的實例是一個手機軟體的實例,對於手機來說,我們可以從手機的品牌進行分類,也可以從軟體角度分類(功能機),同時手機品牌與手機軟體是一個 聚合的關係。 代碼如下: 運行結果: ...
  • ASP.NET MVC5入門基礎,添加一個模型、視圖、控制器,完成增刪改查的功能。 ...
  • 一、前言 上篇運用了.Net Remoting技術解決了本地與伺服器版本對比,並下載更新包的過程。 本篇主要是應用Process,來實現重啟程式的過程。 情景假設: Revit2016正載入某dll,其版本為1.0.0.0。伺服器的更新dll版本為1.0.0.10。 下載完後,Revit2016關閉 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...