轉載自:http://chuansong.me/n/2124760編程
幾年前曾寫過一篇描寫同步/異步以及阻塞/非阻塞的文章,最近再回頭看,還存在一些理解和認知誤區,因而從新整理一下相關的概念,但願對網絡編程的同行能有所啓發。網絡
首先來解釋同步和異步的概念,這兩個概念與消息的通知機制有關。
異步
舉個例子,好比一個用戶去銀行辦理業務,他能夠本身去排隊辦理,也能夠叫人代辦,辦完以後再告知用戶結果。對於要辦理這個銀行業務的人而言,本身去辦理是同步方式,而別人代辦完畢再告知則是異步方式。async
二者的區別在於,同步的方式下,操做者主動完成了這件事情;而異步方式下,調用指令發出後,操做立刻就返回了,操做者並不能立刻知道結果,而是等待所調用的異步過程(在這個例子中是幫忙代辦的人)處理完畢以後,再經過通知手段(在代碼中一般是回調函數)來告訴操做者結果。函數
在上圖的異步 IO 模型中,應用程序調用完 aio_read 以後,不管是否有數據可讀,這個操做都會立刻返回,這個過程至關於這個例子中委託另外一我的去幫忙代辦銀行業務的過程,當數據讀完拷貝到用戶內存以後,會發一個信號通知原進程告訴讀數據操做已經完成(而不只僅是有數據可讀)。
spa
接着解釋阻塞與非阻塞的概念。這兩個概念與程序處理事務時的狀態有關。
3d
一樣用前面的例子,當真正執行辦理業務的人去辦理銀行業務時,前面可能已經有人排隊等候。若是這我的一直從排隊到辦理完畢,中間都沒有作過其餘的事情,那麼這個過程就是阻塞的,這我的當前只在作這麼一件事情。orm
在上圖中,應用程序發起 recvfrom 操做以後,要等待數據拷貝成功才能返回。整個過程當中,不能作其它的操做,這個就是典型的阻塞 IO。blog
反之,若是這我的發現前面排隊的人很多,因而選擇了出去逛逛,過了一會再回來看看有沒有輪到他的號被叫到,若是沒有又繼續出去逛,過一陣再回來看看……如此以往,這個過程就是非阻塞的。由於處理這個事情的人,在這整個過程當中,並無作到除了這件事以外不作別的事情,他的作法是反覆的過來檢測,若是尚未完成就下一次再次嘗試完成這件事情。進程
上圖與前面阻塞 IO 圖的區別在於,當沒有數據可讀時,一樣的 recvfrom 操做返回了錯誤碼,表示當前沒有可讀數據。換言之,即便沒有數據也不會一直讓這個應用阻塞在這個調用上,這就是非阻塞 IO。
到了這裏,能夠先簡單的小結一下這兩組概念
阻塞與非阻塞:區別在於完成一件事情時,當事情尚未完成時,處理這件事情的人除此以外不能再作別的事情;
同步與異步:是本身去作這件事情,仍是等別人作好了來通知有結果,而後再本身去拿結果。注意這裏說的是拿結果,若是隻是別人告訴你能夠作某事,而後本身去操做,這種狀況下也是同步的操做,在後面多路複用I/O中會進行闡述。
可見,兩組概念不是一個維度的概念。咱們把須要辦理銀行業務的人稱爲 A,把代辦理的人稱爲 B,那麼在 A 委託 B 辦理業務的狀況下,假設 A 在交代 B 幫忙辦事以後,A 就去作別的事情,那麼 A 並不存在針對辦理銀行業務這件事情而言是阻塞仍是非阻塞,辦理事務時阻塞與否,是針對真正須要辦理這件事情的人,也就是這個例子裏的 B。
前幾年寫這篇文章時,將多路複用 I/O 類的 select/poll 等和異步操做混爲一談,在這裏特別作一些補充說明。
在之前筆者包括很多同行的理解中,就這個例子而言,列舉下面狀況,當去辦理業務的人,須要排隊時一般都會先去取號,拿到一個紙條的號碼,而後等待銀行叫號。在那個例子裏面,曾經將銀行叫號理解成 select 操做,把紙條比做向 select 註冊的回調函數,一旦能夠進行操做的條件知足,就會根據這個回調函數來通知辦理人,而後辦理人再去完成工做,所以 select 等多路複用操做是異步的行爲。
但上面這種理解最大的錯誤在於,同步與異步的區別在於是否是要求辦理者本身來完成,全部須要本身完成的操做都是同步操做,不論是註冊了一個回調(這裏的叫號小紙條)等待回調你,仍是本身一直阻塞等待。
在上例中,雖然對須要辦理業務的人而言,經過叫號小紙條,他能夠等待銀行的辦理通知。等待的同時能夠去別的事情,好比瀏覽手機上網,但只要能夠辦理該業務的條件知足,真正叫到號能夠辦理業務時,辦理者是須要本身去完成辦理的。
換言之,在完成一件事情時,須要區分處理兩種狀態:一是這個事情是否是能夠作了(條件知足的消息,如 select 告訴你某個文件描述符可讀),另一個是否完成了這件事情(如調用 read/write 完成 IO 操做)。多路複用 IO 記錄下來有哪些人在等待消息的通知,在條件知足時負責通知辦理者,而完成這件事情仍是須要辦理者本身去完成。只要是本身去完成的操做,都是同步的操做。
UNP 的 6.2 節中,最後對異步與同步作的總結很是準確。
POSIX defines these two terms as follows:
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.
Using these definitions, the first four I/O models—blocking, nonblocking, I/O multiplexing, and signal-driven I/O—are all synchronous because the actual I/O operation (recvfrom) blocks the process. Only the asynchronous I/O model matches the asynchronous I/O definition.