自古以來,同步/異步都是八股文第一章

好久沒上線了,今天記錄編程中老掉牙的幾個關鍵術語,一個言簡意賅的術語定義包含主謂賓定狀補, 我們應從貌似雷同的術語中體會到不同術語的表象行爲、側重點。

下面給出的3對技術術語,都是很核心、易混淆的概念點,但是多少還是有些表象、側重點的不同。

書讀百遍其義自見, 請關注最下方給出的微軟官方技術文獻, 自勉!!

1. 同步/異步、 阻塞/非阻塞

阻塞操作不等於同步,非阻塞操作也不等於異步。實際上,它們之間並沒有直接的聯繫。

先說同步,這個很簡單,就是按照代碼來順序執行。

比如下面這段僞代碼:

local res, err  = query-mysql(sql)
local value, err = query-redis(key)

在同一請求連接中,如果要等 MySQL 的查詢結果返回後,才能繼續去查詢 Redis,那就是同步;

如果不用等 MySQL 的返回,就能繼續往下走,去查詢 Redis,那就是異步。

完全不care MYSQL的查詢結果,也不是業務想要的,一般的實踐是query-mysql函數快速返回一個awaitable對象,通過狀態查詢、事件通知的方式拿到異步行爲的結果。


再來說說非阻塞,這是一個很容易和“異步”混淆的概念。

這裏我們說的“阻塞”,特指阻塞操作系統線程

我們繼續看上面的例子,假設查詢 MySQL 需要1s 的時間,如果在這1s 內,操作系統的資源(CPU)是空閒着並傻傻地等待返回,那就是阻塞;

如果 CPU 趁機去處理其他連接的請求,那就是非阻塞。

總體而言:

同步/異步雖然表現爲函數調用,實際宏觀上描述了一信息對齊方式, 異步調用,異步通信,異步任務均表現爲發出通信動作後即刻返回,通過狀態通知、回調函數來拿到通信結果。

阻塞/非阻塞關注的是應用程序在等待數據返回的狀態問題:在得到結果之前,cpu若傻傻等待是阻塞(被掛起)。

.NET異步編程的三種套路

  1. 基於任務的異步模式 (TAP), 主流推薦
  2. 基於事件的異步模式 (EAP), 過時不推薦
  3. 異步編程模型 (APM) 模式(也稱爲 IAsyncResult 模式), 過時不推薦

2,3已經不被推薦(2,3其實很貼近異步的行爲認知),目前主流推薦的TAP async/await語法糖,以同步姿勢簡化了異步編程, 但是語法糖也讓我們不容易理解異步的本質: async/await語法糖具備傳染性,導致async/await在整個代碼結構氾濫使用,在被傳染的async/await層級, 根本不體現通信交互,弱化了開發者對於最底層是異步通信的認知。

微軟喜歡搞拖拽控件、語法糖給到開發者,讓我們沉迷於便利的開發體驗,忽視了樸素的核心本質。


2. 事件/消息

事件是對條件或狀態更改的輕量級通知。

  • 事件的發佈者對如何處理事件沒有期望。
  • 事件的使用者決定如何處理通知。
  • 事件報告狀態變化並且是可操作的, 要進行下一步,消費者只需要知道發生了什麼。事件數據包含關於發生了什麼事情的信息,但不包含觸發事件的數據。例如,事件通知使用者文件已創建。它可能有關於文件的一般信息,但它沒有文件本身。
  • 事件可以是離散的單位,也可以是一系列事件的一部分。
    一系列事件報告了一種狀況,並且是可分析的。這些事件是按時間順序排列並相互關聯的。消費者可通過序列事件來分析發生了什麼。

消息是由服務生成的原始數據,將在其他地方使用或存儲 。

  • 消息包含觸發消息管道的數據。
  • 消息的發佈者對於消費者如何處理消息有一個期望。雙方之間存在一份契約。
    例如,發佈者發送帶有原始數據的消息,並期望消費者從該數據創建文件,並在工作完成時發送響應。

3. 委託/事件

委託更像一個類的一個屬性,只不過屬性值是函數,公開的委託可以像類屬性一樣,自由賦值。

在衆多語言中,委託與閉包密切相關。

和委託類似,事件也是後期綁定機制。 實際上,事件是建立在對委託的語言支持之上。

 In the .NET class library, events are based on the EventHandler delegate and the EventArgs base class.  
public delegate void EventHandler(object? sender, EventArgs e);

後期綁定機制: 組件通過調用可在運行時識別的方法進行通信。 它們都支持單個和多個訂閱服務器方法。 這稱爲單播和多播支持。

兩者均支持用於添加和刪除處理程序的類似語法,引發事件和調用委託也是相同的調用語法。 它們甚至都支持與 ?. 運算符結合的 Invoke() 語法。

使用委託還是事件有一些考量:

事件是對條件或狀態更改的輕量級通知。事件有可能被提前預置了反饋,也可能根本沒預置反饋。

(1). 若偵聽器可選,更傾向事件

A組件引發了事件,也許並不引發其他組件的連鎖反應,也就是沒有預置偵聽器,這種雖然用委託也行,但是更傾向對事件賦值偵聽器。

(2). 事件只能由定義事件的組件自行觸發 ,而不能由外部觸發。

包含事件的類以外的類只能添加和刪除事件偵聽器;只有包含事件的類才能引發事件。
還是那句話,事件更強調組件在滿足條件或自身狀態變更時觸發。

(3). 事件不care偵聽器的返回值

與(1)相關,因爲事件的引發者本身也不care有沒有偵聽器。


結語

搬磚多年,越來越體會到精準理解術語的重要性,一個言簡意賅的術語定義 包含主謂賓定狀補, 我們應從貌似雷同的術語中體會到不同術語的表象行爲、側重點。

上面三對概念:冥冥中存在某種微妙聯繫。

同步/異步: 描述了信息的對齊方式,如果是異步會即時返回,使用狀態通知、回調事件來獲得操作結果。

事件/消息:描述了信息的側重點, 事件強調了某組件在滿足某種條件、時間點而觸發了某次行爲,不care是否有消費方對這個行爲產生了連鎖反應。
消息是生產方要傳遞的原始數據,消息生產方對消息被消費是有期待的(存在消息格式便於消費方理解)。

委託/事件: 更接近於事件的技術實現,事件是基於委託實現的,事件更強調內生引發、委託可認爲是類屬性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章