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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

看过这么多爆文,依旧走不好异步编程这条路?​

發布時間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 看过这么多爆文,依旧走不好异步编程这条路?​ 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊藍字

關注我們

本文帶大家抓住異步編程async/await語法糖的牛鼻子: SynchronizationContext。

引言

C#異步編程語法糖async/await,使開發者很容易就能編寫異步代碼。
零散看過很多文章,很多是填鴨式灌輸 (有的翻譯文還有偏差)。

遵守以上冷冰冰的②③條的原則,一般可確保異步程序按預期運作,

我們時常能在各大論壇看到同學們(因不遵守②③點)引發的死鎖現場。

由async/await引起的死鎖現場

UI程序(WinForm、WPF):點擊按鈕,觸發一個HTTP請求,用請求結果修改UI控件,以下代碼會引發deadlock

public?static?async?Task<string>?GetJsonAsync(Uri?uri) {using?(var?client?=?new?HttpClient()){var?jsonString?=?await?client.GetStringAsync(uri);return?jsonString;} }//?上層調用方法 public?void?Button1_Click(...) {var?jsonTask?=?GetJsonAsync(...);textBox1.Text = jsonTask.Result; }

ASP.NET web程序:從api接口發起HTTP請求,返回請求的結果,以下代碼也會引發deadlock

public?static?async?Task<string>?GetJsonAsync(Uri?uri) {using?(var?client?=?new?HttpClient()){var?jsonString?=?await?client.GetStringAsync(uri);return?jsonString;} } //?上層調用方法 public?class?MyController?:?ApiController {public?string?Get(){var?jsonTask?=?GetJsonAsync(...);return?jsonTask.Result;} }

?? 解決以上死鎖有兩種編程方式:

  • 不再混用異步/同步寫法, 始終使用async/await語法糖編寫異步代碼

  • 對等待的異步任務應用ConfigureAwait(false)方法

  • SynchronizationContext就是這類死鎖的牛鼻子,大多數時候SynchronizationContext是在異步編程后默默工作,但了解這個對象對于理解sync/await工作原理、解決死鎖大有裨益。

    本文會解釋:

  • async/await工作機制

  • SynchronizationContext在異步編程語法糖中的意義

  • 示例代碼為什么會deadlock

  • 1.? await/async語法糖工作機制

    微軟提出Task線程包裝類、 await/async語法糖簡化了異步編程的方式:

    第②步:調用異步方法GetStringAsync時,開啟異步任務;

    第⑥步:遇到await關鍵字,框架會捕獲調用線程的同步上下文(SynchronizationContext)對象, 附加給異步任務;同時控制權上交到上層調用函數;

    第⑦步:異步任務完成,通過IO完成端口通知上層線程, 第⑧步:通過捕獲的線程同步上下文執行后繼代碼塊;

    2.?SynchronizationContext的意義

    先看下MSDN中關于SynchronizationContext的定義:

    提供在各種同步模型中傳播同步上下文的基本功能。此類實現的同步模型的目的是允許公共語言運行庫的內部異步/同步操作使用不同的同步模型正常運行。

    ??這就不是人能看懂的解釋,我給出的解釋是:在線程切換過程中保存調用線程的上下文環境, 用于在異步任務完成后使用此線程同步上下文執行后繼代碼。

    線程同步上下文的意義在哪?

    大家都知道:WinForm和WPF都有類似的原則:長耗時的任務在后臺進行,將異步結果返回給UI線程 。(這難道就是ConfigureAwait方法默認傳true的原因?)

    此時就需要捕獲UI線程的SynchronizationContext,并將這個對象傳入異步任務。

    public?static?void?DoWork() {//On?UI?threadvar?sc?=?SynchronizationContext.Current;ThreadPool.QueueUserWorkItem(delegate{//... async task:do?work?on?ThreadPool????????sc.Post(delegate{//?do?work?on?the?original?context?(UI)},?null);}); }

    SynchronizationContext表示代碼運行的線程環境,在異步編程中,利用該對象切換代碼執行環境。

    不同的.NET框架因各自獨特的線程切換場景有不同的SynchronizationContext子類(重寫父類虛方法):

    • ASP.NET有AspNetSynchronizationContext

    • WinForm有WindowsFormSynchronizationContext

    • WPF 有DispatcherSynchronizationContext

    • ASP.NET Core、控制臺程序不存在SynchronizationContext,SynchronizationContext.Current=null

    AspNetSynchronizationContext維護了HttpContext.Current、用戶身份和文化,但在ASP. NET Core這些信息天然依賴注入,故不再需要SynchronizationContext;另一個好處是不再獲取同步上下文對性能也是一種提升。

    因此,對于ASP.NET Core程序,ConfigureAwait(false)不是必需的,然而,在基礎庫時最好還是使用ConfigureAwait(false),因為你保不準上層會混用同步/異步代碼。

    3. 引言代碼為什么發生deadlock

    觀察引言代碼,控制權返回到上層調用函數時,執行流使用Result/(Wait方法)等待任務結果:Result/Wait()導致調用線程同步阻塞(等待任務完成), 而異步任務執行完成后,會嘗試利用捕獲的同步上下文執行后繼代碼,這樣形成死鎖。

    正因為如此,我們提出兩種方式解決死鎖:

    • 原調用函數始終使用await方法,這樣調用線程是異步等待任務完成,后繼代碼可以在該線程同步上下文上執行

    • 對異步任務應用ConfigureAwait(false)方法

    ConfigureAwait(bool):true ?表示嘗試在捕獲的原調用線程SynchronizationContext 中執行后繼代碼;false 不再嘗試在捕獲的線程SynchronizationContext中執行后繼代碼。?ConfigureAwait(false)? 能解決[因調用線程同步阻塞]引發的死鎖,但是同步阻塞沒有利用異步編程的優點,不是很推薦。

    歸根到底,這兩種解決死鎖的方式都是針對SynchronizationContext;
    ASP. NET Core和控制臺程序,因為捕獲的SynchronizationContext=null, 會選擇一個線程同步上下文來執行,不會死鎖。

    總結

    微軟為加快開發效率上著實費了心力,.NET提供的await/async語法糖簡化了異步編程方式,

    在異步編程中,SynchronizationContext決定了后繼代碼在哪里執行的環境,深入理解這個對象的背景和不同框架的實現方式,能幫助我們避免編寫死鎖代碼。

    # 更多精彩

    • 面試八股文:你寫過自定義任務調度器嗎?

    • 你管這叫"線程安全"?

    • 墻裂推薦:這可能是CAP理論的最好解釋

    • 全網最通透的“閉包”認知 · 跨越語言

    • 鵝廠二面,Nginx回憶錄

    • 實話實說:只會.NET,會讓我們一直處于鄙視鏈、食物鏈的下游

    • 什么是云原生?

    今天因為你的點贊,讓我元氣滿滿!

    總結

    以上是生活随笔為你收集整理的看过这么多爆文,依旧走不好异步编程这条路?​的全部內容,希望文章能夠幫你解決所遇到的問題。

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