同步or異步

1、什麼是同步?什麼是異步?編程

  同步:若是有多個任務要執行,這些任務必須逐個執行,一個任務的執行會致使整個流程的暫時等待,這些任務沒有辦法併發地執行;設計模式

  異步:若是有多個任務要執行,這些任務能夠併發執行,一個任務的執行不會致使整個流程的暫時等待。服務器

  舉個簡單的例子:網絡

  假若有一個任務包括兩個子任務AB,對於同步來講,當A在執行的過程當中,B只有等待,直至A執行完畢,B才能執行;而對於異步就是AB能夠併發地執行,B沒必要等待A執行完畢以後再執行,這樣就不會因爲A的執行致使整個任務的暫時等待。多線程

 

2、什麼是阻塞?什麼是非阻塞?併發

  阻塞:當某個任務在執行過程當中,發出一個請求操做,可是因爲該請求操做須要的條件不知足,那麼就會一直在那等待,直至條件知足;異步

  非阻塞:當某個任務在執行過程當中,發出一個請求操做,若是該請求操做須要的條件不知足,會當即返回一個標誌信息告知條件不知足,不會一直在那等待。socket

  阻塞和非阻塞的區別關鍵在於當發出請求一個操做時,若是條件不知足,是會一直等待仍是返回一個標誌信息。async

  舉個簡單的例子:性能

    假如我要讀取一個文件中的內容,若是此時文件中沒有內容可讀,對於同步來講就是會一直在那等待,直至文件中有內容可讀;而對於非阻塞來講,就會直接返回一個標誌信息告知文件中暫時無內容可讀。

    同步和異步的着重點在於多個任務的執行過程當中,一個任務的執行是否會致使整個流程的暫時等待;

    而阻塞和非阻塞的着重點在於發出一個請求操做時,若是進行操做的條件不知足是否會返會一個標誌信息告知條件不知足。

 

3、什麼是阻塞IO?什麼是非阻塞IO

  一般來講,IO操做包括:對硬盤的讀寫、對socket的讀寫以及外設的讀寫。

  當用戶線程發起一個IO請求操做(本文以讀請求操做爲例),內核會去查看要讀取的數據是否就緒,對於阻塞IO來講,若是數據沒有就緒,則會一直在那等待,直到數據就緒;對於非阻塞IO來講,若是數據沒有就緒,則會返回一個標誌信息告知用戶線程當前要讀的數據沒有就緒。當數據就緒以後,便將數據拷貝到用戶線程,這樣才完成了一個完整的IO讀請求操做,也就是說一個完整的IO讀請求操做包括兩個階段:

  1)查看數據是否就緒;

  2)進行數據拷貝(內核將數據拷貝到用戶線程)。

  那麼阻塞(blocking IO)和非阻塞(non-blocking IO)的區別就在於第一個階段,若是數據沒有就緒,在查看數據是否就緒的過程當中是一直等待,仍是直接返回一個標誌信息。

  Java中傳統的IO都是阻塞IO,好比經過socket來讀數據,調用read()方法以後,若是數據沒有就緒,當前線程就會一直阻塞在read方法調用那裏,直到有數據才返回;而若是是非阻塞IO的話,當數據沒有就緒,read()方法應該返回一個標誌信息,告知當前線程數據沒有就緒,而不是一直在那裏等待。

 

.什麼是同步IO?什麼是異步IO

   咱們先來看一下同步IO和異步IO的定義,在《Unix網絡編程》一書中對同步IO和異步IO的定義是這樣的:

  A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
  An asynchronous I/O operation does not cause the requesting process to be blocked.

  從字面的意思能夠看出:

  同步IO即 若是一個線程請求進行IO操做,在IO操做完成以前,該線程會被阻塞;

  而異步IO爲 若是一個線程請求進行IO操做,IO操做不會致使請求線程被阻塞。

  事實上,同步IO和異步IO模型是針對用戶線程和內核的交互來講的:

  同步IO當用戶發出IO請求操做以後,若是數據沒有就緒,須要經過用戶線程或者內核不斷地去輪詢數據是否就緒,當數據就緒時,再將數據從內核拷貝到用戶線程;

  而異步IO只有IO請求操做的發出是由用戶線程來進行的,IO操做的兩個階段都是由內核自動完成,而後發送通知告知用戶線程IO操做已經完成。也就是說在異步IO中,不會對用戶線程產生任何阻塞。

  

  這是同步IO和異步IO關鍵區別所在

  同步IO和異步IO的關鍵區別反映在數據拷貝階段是由用戶線程完成仍是內核完成。因此說異步IO必需要有操做系統的底層支持。

  注意同步IO和異步IO與阻塞IO和非阻塞IO是不一樣的兩組概念。

  阻塞IO和非阻塞IO是反映在當用戶請求IO操做時,若是數據沒有就緒,是用戶線程一直等待數據就緒,仍是會收到一個標誌信息這一點上面的。也就是說,阻塞IO和非阻塞IO是反映在IO操做的第一個階段,在查看數據是否就緒時是如何處理的。 

 

5、兩種高性能IO設計模式

  在傳統的網絡服務設計模式中,有兩種比較經典的模式:

  一種是 多線程,一種是線程池。

  對於多線程模式,也就說來了client,服務器就會新建一個線程來處理該client的讀寫事件,以下圖所示: 

               

  這種模式雖然處理起來簡單方便,可是因爲服務器爲每一個client的鏈接都採用一個線程去處理,使得資源佔用很是大。所以,當鏈接數量達到上限時,再有用戶請求鏈接,直接會致使資源瓶頸,嚴重的可能會直接致使服務器崩潰。

  所以,爲了解決這種一個線程對應一個客戶端模式帶來的問題,提出了採用線程池的方式,也就說建立一個固定大小的線程池,來一個客戶端,就從線程池取一個空閒線程來處理,當客戶端處理完讀寫操做以後,就交出對線程的佔用。所以這樣就避免爲每個客戶端都要建立線程帶來的資源浪費,使得線程能夠重用。

  可是線程池也有它的弊端,若是鏈接大可能是長鏈接,所以可能會致使在一段時間內,線程池中的線程都被佔用,那麼當再有用戶請求鏈接時,因爲沒有可用的空閒線程來處理,就會致使客戶端鏈接失敗,從而影響用戶體驗。所以,線程池比較適合大量的短鏈接應用。

  所以便出現了下面的兩種高性能IO設計模式:Reactor和Proactor。

  在Reactor模式中,會先對每一個client註冊感興趣的事件,而後有一個線程專門去輪詢每一個client是否有事件發生,當有事件發生時,便順序處理每一個事件,當全部事件處理完以後,便再轉去繼續輪詢,以下圖所示:

       

相關文章
相關標籤/搜索