日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#并发编程之异步编程(二)

發布時間:2023/12/4 C# 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#并发编程之异步编程(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面

前面一篇文章介紹了異步編程的基本內容,同時也簡要說明了async和await的一些用法。本篇文章將對async和await這兩個關鍵字進行深入探討,研究其中的運行機制,實現編碼效率與運行效率的提升。


異步方法描述:使用async修飾符來標識一個方法或Lambda表達式的,被稱之為異步方法。

異步方法編譯:編譯器在遇到await表達式后會截斷方法,并將剩余的異步方法注冊為在等待任務完成后需要繼續執行的后續部分。

異步方法基礎及其運行流程

Async和Await

異步方法使用async修飾,該方法包含一個或多個await表達式或語句,方法同步運行,直至到達第一個?Await,此時暫停,直到等待的任務完成,在任務完成后,控制權返回給方法的調用方。如果方法中并不包含await,則該方法不會像同步方法一樣被掛起。

異步方法通常包含await運算符的一個或多個實例,但缺少await表達式也不會導致生成編譯器錯誤,之會因為沒有await而發出警告,但編譯依然通過。

異步方法使用await關鍵字來確定等待位置,但await表達式并不阻止正在執行到此位置的線程,也就是說異步方法在await表達式執行時只是暫停,并不會導致方法退出,只會導致finally代碼塊不運行。異步方法只有在等待的任務完成后,才能通過該位置并繼續執行剩下的邏輯,控制權也在此處返回給異步方法的調用方。

如果異步方法未使用Await運算符標記暫停點,那么異步方法會作為同步方法執行,即使有Async修飾符,也不例外。如以下示例

1: public async static Task<string> GetUserInfoAsync() 2: { 3: User user = await db.User.FirstOrDefaultAsync();//此處會掛起 4: ? 5: Task<User> user = db.User.FirstOrDefaultAsync();//此處不會掛起,注意此處,返回值也變了,接下來會討論一下異步方法的返回值 6: ? 7: return string.Empty; 8: }
?

具MSDN描述,aysnc關鍵字是一個非保留的關鍵字。在修飾方法或 lambda 表達式時,它是關鍵字,await也作為關鍵字存在。在所有其他上下文中,async和await都會將其解釋為標識符。不過開發人員可以不用太過關注這段,只需要知道aysnc會將一個方法標識成異步方法,而await可以掛起異步方法的執行即可。


關鍵點

1、和被async修飾的方法不一樣,如果方法中含有await關鍵字,方法必須使用async標識符,否則編譯不通過。

2、在異步編程過程中,比較推薦的做法是,被標記了async關鍵字的異步方法應該包含至少一個await表達式或語句。

3、異步方法的命名以Async結尾?

異步返回類型和異常處理

需要說明的是,本文所討論的異步方法指的是基于任務的異步編程模型,返回值是,Task或Task<TResult>。

1、如果方法需要返回string類型,那么將返回Task<string>。如果方法沒有指定返回類型,那么將返回Task。每個返回的任務都表示正在進行的工作,任務封裝有關異步進程狀態的信息,如果未成功,則會引發異常。異步方法返回 Task 或 Task<TResult>。返回任務的屬性攜帶有關其狀態和歷史記錄的信息,如任務是否完成、異步方法是否導致異常或已取消以及最終結果是什么??墒褂胊wait運算符訪問這些屬性。

?

1: public async static Task<User> GetUserInfoAsync() 2: { 3: User user = await db.User.FirstOrDefautAsync(); 4: ? 5: return user; 6: }

2、如果等待的任務返回異步方法導致異常,則 await 運算符會以同步方式拋出異常。如果等待的返回任務的異步方法取消,await運算符引發OperationCanceledException。如果異步方法中沒有使用await阻塞,可以使用try-catch捕捉異常,只是異常發生的時機可能會滯后。

異步方法的運行流程

了解異步方法的運行機制,就是要了解異步編程中的控制流是如何一步步執行的。如果需要詳細了解控制流,可以異步到MSDN中查看。

下圖及其描述摘自MSDN:

關系圖中的數值對應于以下步驟。

  • 事件處理程序調用并等待?AccessTheWebAsync?異步方法。

  • AccessTheWebAsync?創建HttpClient實例并調用GetStringAsync異步方法,獲取的內容字符串方式返回。

  • GetStringAsync?中發生了某種情況,該情況掛起了它的進程??赡鼙仨毜却渌柚谷蝿胀瓿?。為避免阻止資源,GetStringAsync?會將控制權出讓給其調用方?AccessTheWebAsync。?GetStringAsync?返回Task<TResult>,其中 TResult 為字符串,并且?AccessTheWebAsync?將任務分配給?getStringTask?變量。該任務將調用GetStringAsync正在進行的進程,在調用完成時產生返回字符串給urlcontent。

  • 由于尚未等待?getStringTask,因此,AccessTheWebAsync?可以繼續執行而不依賴于?GetStringAsync?最終結果的完成。該任務繼續調用同步方法?DoIndependentWork。

  • DoIndependentWork?作為一個同步方法,在自身工作完成后返回到調用方。

  • AccessTheWebAsync?已運行完畢,可以不受?getStringTask?的結果影響。接下來,AccessTheWebAsync?需要計算并返回已下載的字符串的長度,但該方法只有在獲得字符串的情況下才能計算該值。

    因此,AccessTheWebAsync?使用一個 await 運算符來掛起其任務,并把控制權交給調用?AccessTheWebAsync?的事件處理程序。?AccessTheWebAsync?將?Task<int>返回給調用方。該任務將計算下載字符串長度。?

  • GetStringAsync?完成并生成一個字符串結果。字符串結果不是通過按你預期的方式調用?GetStringAsync?所返回的。(記住,該方法已返回步驟 3 中的一個任務)。相反,字符串結果存儲在表示?getStringTask?方法完成的任務中。await 運算符從?getStringTask?中檢索結果。賦值語句將檢索到的結果賦給?urlContents。

  • 當?AccessTheWebAsync?獲取字符串結果時,該方法可以計算字符串長度。然后,AccessTheWebAsync?工作也將完成,并且等待事件處理程序的繼續使用。事件處理程序也將最終獲得字符串的長度信息。

  • 注意:

    如果 GetStringAsync(因此 getStringTask)在 AccessTheWebAsync 等待前完成,則控制權會保留在 AccessTheWebAsync中。如果異步調用過程 (AccessTheWebAsync) 已完成,并且 AccessTheWebSync 不必等待最終結果,則掛起然后返回到 getStringTask 將造成資源浪費。

    在調用方內部(此示例中的事件處理程序),處理模式將繼續。在等待結果前,調用方可以開展不依賴于 AccessTheWebAsync 結果的其他工作,否則就需等待片刻。事件處理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。

    異步編程對性能的影響

    ?在.NET異步編程中,async和await不會創建其他線程,同時異步方法不會在其自身線程上運行,因此它不需要多線程。只有當方法處于活動狀態時,該方法將在當前同步上下文中運行并使用線程上的時間??梢允褂肨ask.Run將占用大量CPU的工作移到后臺線程,但是后臺線程不會幫助正在等待結果的進程變為可用狀態。

    對于異步編程而言,基于異步的方法優于幾乎每個用例中的現有方法。具體而言,這種方法優于BackgroundWorker的I/O綁定操作因為代碼更簡單且無需防止爭用條件。結合Task.Run使用時,異步編程比BackgroundWorker更適用于CPU綁定的操作,因為異步編程將運行代碼的協調細節與Task.Run傳輸至線程池的工作區分開來。

    那么異步編程對線程的影響又是什么呢,相比大家應該都知道,ASP.NET中有兩類線程,工作線程,和IO線程。

    其中工作線程處理普通請求的線程,也是我們用得最多的線程。這個線程是有限的,是根CPU的個數相關的。IO線程,比如與文件讀寫,網絡操作等是可以異步實現并且使性能提升的地方。I/O線程通常情況下是空閑的。所以可以使用IO線程來代替工作線程,一方面充分運用了系統資源,另一方面也節省了工作線程調度及切換所帶來的損耗。

    由此我們需要明白,在I/O密集型處理時,使用異步可以帶來很大的提升,比如數據庫操作以及網絡操作。

    即便異步編程帶來性能的提升,但是運用不慎,也會對系統性能產生反作用,比如直接使用Task.Run或者Task.Factory.StartNew所帶來的異步編程,這些方式會占用工作線程以及工作線程之間的切換。?

    異步編程需要注意的地方


    1、同時async和await侵入性或者傳遞性很強,所有調用的地方都需要同步使用async和await,這對系統中老代碼的修改產生了很大的影響。

    2、異步編程中無法使用lock鎖,因為異步方法不會在自身線程上運行,lock就變成了多余的了。但異步編程場景下可以使用AsyncLock鎖,對相應的代碼進行鎖定。

    3、異步編程里,比較推薦的做法是避免上線文延續,此處不再做更多說明,參考我的前一篇文章《異步編程(一)》

    4、異步編程是否真的提升了系統性能,目前來看大多數場景下是提升了,尤其在I/O操作比較密集的業務場景下,比如查詢數據庫和網絡調用。


    總結

    以上是生活随笔為你收集整理的C#并发编程之异步编程(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。