自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看過這么多爆文,依舊走不好異步編程這條路?

開發(fā) 前端
在異步編程中,SynchronizationContext決定了后繼代碼在哪里執(zhí)行的環(huán)境,深入理解這個(gè)對(duì)象的背景和不同框架的實(shí)現(xiàn)方式,能幫助我們避免編寫死鎖代碼。

[[401828]]

本文轉(zhuǎn)載自微信公眾號(hào)「精益碼農(nóng)」,作者精益碼農(nóng)。轉(zhuǎn)載本文請(qǐng)聯(lián)系精益碼農(nóng)公眾號(hào)。

引言

C#異步編程語(yǔ)法糖async/await,使開發(fā)者很容易就能編寫異步代碼。

零散看過很多文章,很多是填鴨式灌輸 (有的翻譯文還有偏差)。

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

我們時(shí)常能在各大論壇看到同學(xué)們(因不遵守②③點(diǎn))引發(fā)的死鎖現(xiàn)場(chǎng)。

由async/await引起的死鎖現(xiàn)場(chǎng)

UI程序(WinForm、WPF):點(diǎn)擊按鈕,觸發(fā)一個(gè)HTTP請(qǐng)求,用請(qǐng)求結(jié)果修改UI控件,以下代碼會(huì)引發(fā)deadlock

  1. public static async Task<string> GetJsonAsync(Uri uri) 
  2.   using (var client = new HttpClient()) 
  3.   { 
  4.     var jsonString = await client.GetStringAsync(uri); 
  5.     return jsonString; 
  6.   } 
  7.  
  8. // 上層調(diào)用方法 
  9. public void Button1_Click(...) 
  10.   var jsonTask = GetJsonAsync(...); 
  11.   textBox1.Text = jsonTask.Result; 

ASP.NET web程序:從api接口發(fā)起HTTP請(qǐng)求,返回請(qǐng)求的結(jié)果,以下代碼也會(huì)引發(fā)deadlock

  1. public static async Task<string> GetJsonAsync(Uri uri) 
  2.   using (var client = new HttpClient()) 
  3.   { 
  4.     var jsonString = await client.GetStringAsync(uri); 
  5.     return jsonString; 
  6.   } 
  7. // 上層調(diào)用方法 
  8. public class MyController : ApiController 
  9.   public string Get() 
  10.   { 
  11.     var jsonTask = GetJsonAsync(...); 
  12.     return jsonTask.Result; 
  13.   } 
  • 解決以上死鎖有兩種編程方式:
  1. 不再混用異步/同步寫法, 始終使用async/await語(yǔ)法糖編寫異步代碼
  2. 對(duì)等待的異步任務(wù)應(yīng)用ConfigureAwait(false)方法

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

本文會(huì)解釋:

  • async/await工作機(jī)制
  • SynchronizationContext在異步編程語(yǔ)法糖中的意義
  • 示例代碼為什么會(huì)deadlock

1. await/async語(yǔ)法糖工作機(jī)制

微軟提出Task線程包裝類、 await/async語(yǔ)法糖簡(jiǎn)化了異步編程的方式:

第②步:調(diào)用異步方法GetStringAsync時(shí),開啟異步任務(wù);

第⑥步:遇到await關(guān)鍵字,框架會(huì)捕獲調(diào)用線程的同步上下文(SynchronizationContext)對(duì)象, 附加給異步任務(wù);同時(shí)控制權(quán)上交到上層調(diào)用函數(shù);

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

2. SynchronizationContext的意義

先看下MSDN中關(guān)于SynchronizationContext的定義:

提供在各種同步模型中傳播同步上下文的基本功能。此類實(shí)現(xiàn)的同步模型的目的是允許公共語(yǔ)言運(yùn)行庫(kù)的內(nèi)部異步/同步操作使用不同的同步模型正常運(yùn)行。

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

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

大家都知道:WinForm和WPF都有類似的原則:長(zhǎng)耗時(shí)的任務(wù)在后臺(tái)進(jìn)行,將異步結(jié)果返回給UI線程 。(這難道就是ConfigureAwait方法默認(rèn)傳true的原因?)

此時(shí)就需要捕獲UI線程的SynchronizationContext,并將這個(gè)對(duì)象傳入異步任務(wù)。

  1. public static void DoWork() 
  2.     //On UI thread 
  3.     var sc = SynchronizationContext.Current
  4.  
  5.     ThreadPool.QueueUserWorkItem(delegate 
  6.     { 
  7.         //... async task:do work on ThreadPool 
  8.         sc.Post(delegate 
  9.         { 
  10.              // do work on the original context (UI) 
  11.         }, null); 
  12.     }); 

SynchronizationContext表示代碼運(yùn)行的線程環(huán)境,在異步編程中,利用該對(duì)象切換代碼執(zhí)行環(huán)境。

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

  • ASP.NET有AspNetSynchronizationContext
  • WinForm有WindowsFormSynchronizationContext
  • WPF 有DispatcherSynchronizationContext
  • ASP.NET Core、控制臺(tái)程序不存在SynchronizationContext,SynchronizationContext.Current=null

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

因此,對(duì)于ASP.NET Core程序,ConfigureAwait(false)不是必需的,然而,在基礎(chǔ)庫(kù)時(shí)最好還是使用ConfigureAwait(false),因?yàn)槟惚2粶?zhǔn)上層會(huì)混用同步/異步代碼。

3. 引言代碼為什么發(fā)生deadlock

觀察引言代碼,控制權(quán)返回到上層調(diào)用函數(shù)時(shí),執(zhí)行流使用Result/(Wait方法)等待任務(wù)結(jié)果:Result/Wait()導(dǎo)致調(diào)用線程同步阻塞(等待任務(wù)完成), 而異步任務(wù)執(zhí)行完成后,會(huì)嘗試?yán)貌东@的同步上下文執(zhí)行后繼代碼,這樣形成死鎖。

正因?yàn)槿绱?,我們提出兩種方式解決死鎖:

  • 原調(diào)用函數(shù)始終使用await方法,這樣調(diào)用線程是異步等待任務(wù)完成,后繼代碼可以在該線程同步上下文上執(zhí)行
  • 對(duì)異步任務(wù)應(yīng)用ConfigureAwait(false)方法

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

歸根到底,這兩種解決死鎖的方式都是針對(duì)SynchronizationContext;

ASP. NET Core和控制臺(tái)程序,因?yàn)椴东@的SynchronizationContext=null, 會(huì)選擇一個(gè)線程同步上下文來執(zhí)行,不會(huì)死鎖。

總結(jié)

微軟為加快開發(fā)效率上著實(shí)費(fèi)了心力,.NET提供的await/async語(yǔ)法糖簡(jiǎn)化了異步編程方式,

 

在異步編程中,SynchronizationContext決定了后繼代碼在哪里執(zhí)行的環(huán)境,深入理解這個(gè)對(duì)象的背景和不同框架的實(shí)現(xiàn)方式,能幫助我們避免編寫死鎖代碼。

 

責(zé)任編輯:武曉燕 來源: 精益碼農(nóng)
相關(guān)推薦

2022-07-26 23:43:29

編程語(yǔ)言開發(fā)Java

2020-09-04 08:13:32

網(wǎng)絡(luò)安全電商行業(yè)安全產(chǎn)品

2013-01-15 09:41:45

編程語(yǔ)言

2024-04-02 08:41:10

ArrayListSubList場(chǎng)景

2017-08-11 14:21:33

軟件開發(fā)前端框架

2023-07-17 08:21:52

漏洞版本項(xiàng)目

2018-06-26 15:00:24

Docker安全風(fēng)險(xiǎn)

2024-07-12 09:35:38

前端工具檢驗(yàn)

2023-11-13 08:49:54

2024-02-20 08:09:51

Java 8DateUtilsDate工具類

2017-12-21 19:38:50

潤(rùn)乾中間表

2021-01-14 05:08:44

編譯鏈接

2021-01-29 08:52:10

App微信移動(dòng)應(yīng)用

2020-08-31 06:43:13

Redis集群模式

2021-01-14 10:24:55

壓縮集合方式

2020-11-20 10:22:34

代碼規(guī)范設(shè)計(jì)

2021-05-11 07:42:59

BeanSpring屬性

2022-11-09 10:32:50

群業(yè)務(wù)群聊數(shù)據(jù)結(jié)構(gòu)

2018-02-01 07:16:08

布線電線線路

2019-01-31 10:15:14

群聊單聊消息
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)