同步、異步、阻塞、非阻塞與服務器


最近在折騰服務器框架相關問題,學了東西不記下來很快會忘記……html

OS中的同步、異步、阻塞、非阻塞

OS的I/O流程是這樣的:python

  1. CPU發出I/O操做的通知;
  2. 文件系統或其餘會調用相關設備執行這些操做;
  3. 最後當數據到達用戶空間後發出一箇中斷的完成標誌;

在這個從CPU發出調用到收到完成標誌的過程當中就存在一個時間差,如今就有了兩個重要的概念:完成標誌與時間差。服務器

  • 同步與異步是針對獲取完成標誌
  • 阻塞與非阻塞是針對時間差

因此有這樣的定義:多線程

  • 同步與異步:獲取完成標誌的方式。若是是採用輪詢的方式監測I/O操做是否完成稱爲同步,而以經過回調通知的方式得到完成標誌則稱爲異步。
  • 阻塞與非阻塞:在那段時間差的過程當中,CPU有沒有處理別的事情,若是處理過別的事情則是非阻塞,若是並無處理過別的事情則是阻塞。

I/O控制方式有哪幾種?
1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)--> 輪詢
3) I/O複用(select 和poll) (I/O multiplexing)
4)信號驅動I/O (signal driven I/O (SIGIO))
5)異步I/O (asynchronous I/O (the POSIX aio_functions)) --> 回調
看圖便於理解:

出自:Linux的五種I/O模式併發

幾種常見服務器模型:

下面咱們談談服務器,服務器模型也能夠基於異步、同步、阻塞、非阻塞這四個概念框架

  • 同步式:一次處理一個請求,其他請求處於等待狀態
  • 每請求/每進程: 爲每一個請求啓動一個進程【不具有擴展功能,系統志願有限】
  • 每請求/每線程:爲每一個請求啓動一個線程【每一個線程佔必定內存,故受限於內存,還會拖慢服務器】【Apache就是採用的這種方式】
  • 事件驅動:Node與Nginx採用事件驅動方式而不建立新線程【省去了線程建立/刪除的系統開銷以及線程上下文切換,因此可以處理更多的鏈接】【python的Twisted,Ruby的Event Machine以及Perl的AyEvent也是事件驅動,可是他們並非很成功】

須要注意的是對於高併發的程序每每採用「同步非阻塞」而不是「多線程的同步阻塞」,在合理設計任務調度的不一樣階段可以使得併發數遠大於並行數,須要注意的是在高併發情況下爲每一個任務建立一個線程的開銷很大,因此並不採用多線程的同步阻塞。異步

併發:同時進行的任務數量
並行:可同時工做的物理資源(CPU核數等等)async

另外,有個概念是異步IO,其主要是說在同一線程中當遭遇IO時,並不等待而是執行下面的操做直到IO操做完成後再切回當前,其實就是同步非阻塞,在廖雪峯老師的博客中提到這樣一個模型:
異步IO模型須要一個消息循環,在消息循環中,主線程不斷地重複「讀取消息-處理消息」這一過程:高併發

loop = get_event_loop()
while True:
    event = loop.get_event()
    process_event(event)

消息模型其實早在應用在桌面應用程序中了。一個GUI程序的主線程就負責不停地讀取消息並處理消息。全部的鍵盤、鼠標等消息都被髮送到GUI程序的消息隊列中,而後由GUI程序的主線程處理。oop

因爲GUI線程處理鍵盤、鼠標等消息的速度很是快,因此用戶感受不到延遲。某些時候,GUI線程在一個消息處理的過程當中遇到問題致使一次消息處理時間過長,此時,用戶會感受到整個GUI程序中止響應了,敲鍵盤、點鼠標都沒有反應。這種狀況說明在消息模型中,處理一個消息必須很是迅速,不然,主線程將沒法及時處理消息隊列中的其餘消息,致使程序看上去中止響應。

消息模型是如何解決同步IO必須等待IO操做這一問題的呢?當遇到IO操做時,代碼只負責發出IO請求,不等待IO結果,而後直接結束本輪消息處理,進入下一輪消息處理過程。當IO操做完成後,將收到一條「IO完成」的消息,處理該消息時就能夠直接獲取IO操做結果。

在「發出IO請求」到收到「IO完成」的這段時間裏,同步IO模型下,主線程只能掛起,但異步IO模型下,主線程並無休息,而是在消息循環中繼續處理其餘消息。這樣,在異步IO模型下,一個線程就能夠同時處理多個IO請求,而且沒有切換線程的操做。對於大多數IO密集型的應用程序,使用異步IO將大大提高系統的多任務處理能力。

相關資料

Linux的五種I/O模式
廖雪峯Python-異步I/O
同步,異步,阻塞,非阻塞以及幾種常見的服務器模型

相關文章
相關標籤/搜索