C# 同步和異步(概念理解)


C#  同步和異步

IO 概念區分

四個相關概念:

 

  1. 同步(Synchronous)
  2. 異步( Asynchronous)
  3. 阻塞( Blocking )
  4. 非阻塞( Nonblocking)

 

同步異步圖解

 

通俗理解 (易懂)

同步異步 指的是在客戶端

同步意味着 客戶端提出了一個請求以后,在回應之前只能等待

異步意味着 客戶端提出一個請求以后,還可以繼續提其他請求

阻塞非阻塞 指的是服務器端

阻塞意味着 服務器接受一個請求后,在返回結果以前不能接受其他請求

非阻塞意味着 服務器接受一個請求后,盡管沒有返回結果,還是可以繼續接受其他請求

同步異步側重點(關鍵)

 

 

 

1.同步與異步 :關注的是消息通信機制


同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個*調用*時,在沒有得到結果之前,該*調用*就不返回。但是一旦調用返回,就得到返回值了。
換句話說,就是由*調用者*主動等待這個*調用*的結果。

而異步則是相反,*調用*在發出之后,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出后,調用者不會立刻得到結果。

而是在*調用*發出后,*被調用者*通過狀態、通知來通知調用者,或通過回調函數處理這個調用。

典型的異步編程模型比如Node.js

舉個通俗的例子:

同步通信機制
你打電話問書店老板有沒有《分布式系統》這本書,如果是同步通信機制,書店老板會說,你稍等,”我查一下",然后開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。


異步通信機制

書店老板直接告訴你我查一下啊,查好了打電話給你,然后直接掛電話了(不返回結果)。然后查好了,他會主動打電話給你。在這里老板通過“回電”這種方式來回調。

2. 阻塞與非阻塞:關注的是程序在等待調用結果(消息,返回值)時的狀態.


阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.

阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之后才會返回。
非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。

還是上面的例子,
你打電話問書店老板有沒有《分布式系統》這本書,你如果是阻塞式調用,你會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式調用,你不管老板有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鍾check一下老板有沒有返回結果。
在這里阻塞與非阻塞與是否同步異步無關。跟老板通過什么方式回答你結果無關。

不同模型的理解

為了更好的理解異步編程模型的特點,我們來回顧一下兩個大家都熟悉的模型。在闡述過程中,我們假設一個包含三個相互獨立任務的程序。在此,除了規定這些任務都要完成自己工作外,我們先不作具體的解釋,后面我們會慢慢具體了解它們。請注意:在此我用"任務"這個詞,這意味着它需要完成一些事情。

第一個模型是單線程的同步模型,如圖1所示:

https://pic3.zhimg.com/80/v2-7e4074a08d2a71f1e34fc06345b39c3a_hd.png

 

圖1 同步模型

這是最簡單的編程方式。在一個時刻,只能有一個任務在執行,並且前一個任務結束后一個任務才能開始。如果任務都能按照事先規定好的順序執行,最后一個任務的完成意味着前面所有的任務都已無任何差錯地完成並輸出其可用的結果—這是多么簡單的邏輯。 下面我們來呈現第二個模型,如圖2所示:

 

https://pic3.zhimg.com/80/v2-9650f6ec85ce822e41c5edc21c5a3dde_hd.png

 

 

圖2 線程模型

在這個模型中,每個任務都在單獨的線程中完成。這些線程都是由操作系統來管理,若在多處理機、多核處理機的系統中可能會相互獨立的運行,若在單處理機上,則會交錯運行。關鍵點在於,在線程模式中,具體哪個任務執行由操作系統來處理。但編程人員則只需簡單地認為:它們的指令流是相互獨立且可以並行執行。雖然,從圖示看起來很簡單,實際上多線程編程是很麻煩的,你想啊,任務之間的要通信就要是線程之間的通信。線程間的通信那不是一般的復雜。什么郵槽、通道、共享內存。。。 唉—__-

一些程序用多處理機而不是多線程來實現並行運算。雖然具體的編程細節是不同的,但對於我們要研究的模型來說是一樣的。

下面我們來介紹一下異步編程模型,如圖3所示

https://pic1.zhimg.com/80/v2-a86781d839b0ae665753d370e363d6c8_hd.png

 

圖3 異步模型

在這個模型中,任務是交錯完成,值得注意的是:這是在單線程的控制下。這要比多線程模型簡單多了,因為編程人員總可以認為只有一個任務在執行,而其它的在停止狀態。雖然在單處理機系統中,線程也是像圖3那樣交替進行。但作為程序員在使用多線程時,仍然需要使用圖2而不是圖3的來思考問題,以防止程序在挪到多處理機的系統上無法正常運行(考慮到兼容性)。但單線程的異步程序不管是在單處理機還是在多處理機上都能很好的運行。

在異步編程模型與多線程模型之間還有一個不同:在多線程程序中,對於停止某個線程啟動另外一個線程,其決定權並不在程序員手里而在操作系統那里,因此,程序員在編寫程序過程中必須要假設在任何時候一個線程都有可能被停止而啟動另外一個線程。相反,在異步模型中,一個任務要想運行必須顯式放棄當前運行的任務的控制權。這也是相比多線程模型來說,最簡潔的地方。 值得注意的是:將異步編程模型與同步模型混合在同一個系統中是可以的。但在介紹中的絕大多數時候,我們只研究在單個線程中的異步編程模型。

動機

我們已經看到異步編程模型之所以比多線程模型簡單在於其單指令流與顯式地放棄對任務的控制權而不是被操作系統隨機地停止。但是異步模型要比同步模型復雜得多。程序員必須將任務組織成序列來交替的小步完成。因此,若其中一個任務用到另外一個任務的輸出,則依賴的任務(即接收輸出的任務)需要被設計成為要接收系列比特或分片而不是一下全部接收。由於沒有實質上的並行,從我們的圖中可以看出,一個異步程序會花費一個同步程序所需要的時間,可能會由於異步程序的性能問題而花費更長的時間。

因此,就要問了,為什么還要使用異步模型呢? 在這兒,我們至少有兩個原因。首先,如果有一到兩個任務需要完成面向人的接口,如果交替執行這些任務,系統在保持對用戶響應的同時在后台執行其它的任務。因此,雖然后台的任務可能不會運行的更快,但這樣的系統可能會受歡迎的多。

然而,有一種情況下,異步模型的性能會高於同步模型,有時甚至會非常突出,即在比較短的時間內完成所有的任務。這種情況就是任務被強行等待或阻塞,如圖4所示:

https://pic1.zhimg.com/80/v2-da912604a68dff7add9a1780d95728e8_hd.png

 

圖4 同步模型中出現阻塞

在圖4中,灰色的部分代表這段時間某個任務被阻塞。為什么要阻塞一個任務呢?最直接的原因就是等待I/O的完成:傳輸數據或來自某個外部設備。一個典型的CPU處理數據的能力是硬盤或網絡的幾個數量級的倍數。因此,一個需要進行大I/O操作的同步程序需要花費大量的時間等待硬盤或網絡將數據准備好。正是由於這個原因,同步程序也被稱作為阻塞程序。

從圖4中可以看出,一個可阻塞的程序,看起來與圖3描述的異步程序有點像。這不是個巧合。異步程序背后的最主要的特點就在於,當出現一個任務像在同步程序一樣出現阻塞時,會讓其它可以執行的任務繼續執行,而不會像同步程序中那樣全部阻塞掉。因此一個異步程序只有在沒有任務可執行時才會出現"阻塞",這也是為什么異步程序被稱為非阻塞程序的原因。 任務之間的切換要不是此任務完成,要不就是它被阻塞。由於大量任務可能會被阻塞,異步程序等待的時間少於同步程序而將這些時間用於其它實時工作的處理(如與人打交道的接口),這樣一來,前者的性能必然要高很多。

與同步模型相比,異步模型的優勢在如下情況下會得到發揮:

  1. 有大量的任務,以至於可以認為在一個時刻至少有一個任務要運行
  2. 任務執行大量的I/O操作,這樣同步模型就會在因為任務阻塞而浪費大量的時間
  3. 任務之間相互獨立,以至於任務內部的交互很少。

這些條件大多在CS模式中的網絡比較繁忙的服務器端出現(如WEB服務器)。每個任務代表一個客戶端進行接收請求並回復的I/O操作。客戶的請求(相當於讀操作)都是相互獨立的。因此一個網絡服務是異步模型的典型代表,這也是為什么twisted是第一個也是最棒的網絡庫。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM