也許不少朋友在學習NIO的時候都會感受有點吃力,對裏面的不少概念都感受不是那麼明朗。在進入Java NIO編程以前,咱們今天先來討論一些比較基礎的知識:I/O模型。下面本文先從同步和異步的概念 提及,而後接着闡述了阻塞和非阻塞的區別,接着介紹了阻塞IO和非阻塞IO的區別,而後介紹了同步IO和異步IO的區別,接下來介紹了5種IO模型,最後介紹了兩種和高性能IO設計相關的設計模式(Reactor和Proactor)。html
如下是本文的目錄大綱:編程
一.什麼是同步?什麼是異步?設計模式
二.什麼是阻塞?什麼是非阻塞?服務器
三.什麼是阻塞IO?什麼是非阻塞IO?網絡
四.什麼是同步IO?什麼是異步IO?多線程
五.五種IO模型併發
六.兩種高性能IO設計模式((Reactor和Proactor))異步
什麼是同步?什麼是異步?
同步和異步的概念出來已經好久了,網上有關同步和異步的說法也有不少。如下是我我的的理解:socket
同步就是:若是有多個任務或者事件要發生,這些任務或者事件必須逐個地進行,一個事件或者任務的執行會致使整個流程的暫時等待,這些事件沒有辦法併發地執行;async
異步就是:若是有多個任務或者事件發生,這些事件能夠併發地執行,一個事件或者任務的執行不會致使整個流程的暫時等待。
這就是同步和異步。舉個簡單的例子,假若有一個任務包括兩個子任務A和B,對於同步來講,當A在執行的過程當中,B只有等待,直至A執行完畢,B才能執行;而對於異步就是A和B能夠併發地執行,B沒必要等待A執行完畢以後再執行,這樣就不會因爲A的執行致使整個任務的暫時等待。
若是還不理解,能夠先看下面這2段代碼:
void fun1() {
}
void fun2() {
}
void function(){ fun1(); fun2() ..... ..... } |
上面的代碼中,fun2必須等待fun1執行完以後,它才能執行,所是這兩個操做是同步的。
接着看下面這段代碼:
void fun1() {
}
void fun2() {
}
void function(){ new Thread(){ public void run() { fun1(); } }.start();
new Thread(){ public void run() { fun2(); } }.start();
..... ..... } |
這段代碼是一種典型的異步,fun1的執行不會影響到fun2的執行,而且fun1和fun2的執行不會致使其後續的執行過程處於暫時的等待。
事實上,同步和異步是一個很是廣的概念,它們的重點在於多個任務和事件發生時,一個事件的發生或執行是否會致使整個流程的暫時等待。我以爲能夠將同步和異步與Java中的synchronized關鍵字聯繫起來進行類比。當多個線程同時訪問一個變量時,每一個線程訪問該變量就是一個事件,對於同步來講,就是這些線程必須逐個地來訪問該變量,一個線程在訪問該變量的過程當中,其餘線程必須等待;而對於異步來講,就是多個線程沒必要逐個地訪問該變量,能夠同時進行訪問。
所以,我的以爲同步和異步能夠表如今不少方面,可是記住其關鍵在於多個任務和事件發生時,一個事件的發生或執行是否會致使整個流程的暫時等待。通常來講,能夠經過多線程的方式來實現異步,可是千萬記住不要將多線程和異步畫上等號,異步只是宏觀上的一個模式,採用多線程來實現異步只是一種手段,而且經過多進程的方式也能夠實現異步。
在遊戲服務器裏面,通常來講同一個用戶的操做都應該是同步的,也就是說同個用戶操做必須按順序執行,這樣以保證同一個用戶數據的正確性,由於數據的修改是有順序性的。而對於不一樣的用戶,他們之間的操做是不相關的,徹底能夠採用異步的方式,這樣一個用戶的操做不會等待另外一個用戶操做完成,不會形成一個用戶卡另外一個用戶的狀況,增長服務器處理多個客戶端數據的效率。
什麼是阻塞?什麼是非阻塞?
在前面介紹了同步和異步的區別,這一節來看一下阻塞和非阻塞的區別。
阻塞就是:當某個事件或者任務在執行過程當中,它發出一個請求操做,可是因爲該請求操做須要的條件不知足,那麼就會一直在那等待,直至條件知足;
非阻塞就是:當某個事件或者任務在執行過程當中,它發出一個請求操做,若是該請求操做須要的條件不知足,會當即返回一個標誌信息告知條件不知足,不會一直在那等待。
這就是阻塞和非阻塞的區別。也就是說阻塞和非阻塞的區別關鍵在於當發出請求一個操做時,若是條件不知足,是會一直等待仍是返回一個標誌信息。
舉個簡單的例子:在遊戲服務器開發中,咱們會用到消息隊列的機制,即生產者消費者模式,消費者在消息隊列取消息,若是隊列中沒有消息,阻塞就是取的操做不返回,在那一直等待,直到有消息隊列中來了新數據,非阻塞就是,若是發現沒有數據,就當即返回null,處理其它的數據。
在網上有一些朋友將同步和異步分別與阻塞和非阻塞畫上等號,事實上,它們是兩組徹底不一樣的概念。注意,理解這兩組概念的區別對於後面IO模型的理解很是重要。
同步和異步着重點在於多個任務的執行過程當中,一個任務的執行是否會致使整個流程的暫時等待;而阻塞和非阻塞着重點在於發出一個請求操做時,若是進行操做的條件不知足是否會返會一個標誌信息告知條件不知足。理解阻塞和非阻塞能夠同線程阻塞類比地理解,當一個線程進行一個請求操做時,若是條件不知足,則會被阻塞,即在那等待條件知足。
什麼是阻塞IO?什麼是非阻塞IO?
在瞭解阻塞IO和非阻塞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操做的第一個階段,在查看數據是否就緒時是如何處理的。
轉載請註明來自:http://www.youxijishu.com/h-nd-140-2_323.html
更多有關遊戲技術方面的問題,請參考網站:http://www.youxijishu.com